Add executive meeting management system with role-based access
Implement a new API endpoint and UI for managing executive meetings, including role-based access control and database schema changes for meeting data and attendees. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: 079afca5-8c32-40ea-b7d1-8bf26358ff75 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/BRoHDEI Replit-Helium-Checkpoint-Created: true
This commit is contained in:
@@ -13,6 +13,8 @@ import {
|
||||
userGroupsTable,
|
||||
groupAppsTable,
|
||||
groupRolesTable,
|
||||
executiveMeetingsTable,
|
||||
executiveMeetingAttendeesTable,
|
||||
} from "@workspace/db";
|
||||
import { eq } from "drizzle-orm";
|
||||
import bcrypt from "bcryptjs";
|
||||
@@ -232,6 +234,19 @@ async function main() {
|
||||
isSystem: false,
|
||||
sortOrder: 6,
|
||||
},
|
||||
{
|
||||
slug: "executive-meetings",
|
||||
nameAr: "إدارة الاجتماعات التنفيذية",
|
||||
nameEn: "Executive Meetings",
|
||||
descriptionAr: "جدولة اجتماعات المكتب التنفيذي ومتابعتها",
|
||||
descriptionEn: "Schedule and track executive office meetings",
|
||||
iconName: "CalendarClock",
|
||||
route: "/executive-meetings",
|
||||
color: "#0B1E3F",
|
||||
isActive: true,
|
||||
isSystem: false,
|
||||
sortOrder: 7,
|
||||
},
|
||||
];
|
||||
|
||||
const insertedApps = await db.insert(appsTable).values(apps).onConflictDoNothing().returning();
|
||||
@@ -436,6 +451,256 @@ async function main() {
|
||||
}
|
||||
console.log("Groups created and existing users mapped");
|
||||
|
||||
// Executive meetings: roles
|
||||
const execRoles = [
|
||||
{
|
||||
name: "executive_ceo",
|
||||
descriptionAr: "الرئيس التنفيذي",
|
||||
descriptionEn: "Chief Executive Officer",
|
||||
isSystem: 1,
|
||||
},
|
||||
{
|
||||
name: "executive_office_manager",
|
||||
descriptionAr: "مدير المكتب التنفيذي",
|
||||
descriptionEn: "Executive Office Manager",
|
||||
isSystem: 1,
|
||||
},
|
||||
{
|
||||
name: "executive_coord_lead",
|
||||
descriptionAr: "رئيس التنسيق والتوثيق",
|
||||
descriptionEn: "Coordination Lead",
|
||||
isSystem: 1,
|
||||
},
|
||||
{
|
||||
name: "executive_coordinator",
|
||||
descriptionAr: "منسق المكتب التنفيذي",
|
||||
descriptionEn: "Executive Coordinator",
|
||||
isSystem: 1,
|
||||
},
|
||||
{
|
||||
name: "executive_viewer",
|
||||
descriptionAr: "مشاهد الاجتماعات التنفيذية",
|
||||
descriptionEn: "Executive Meetings Viewer",
|
||||
isSystem: 1,
|
||||
},
|
||||
];
|
||||
await db.insert(rolesTable).values(execRoles).onConflictDoNothing();
|
||||
console.log("Executive Meetings roles created");
|
||||
|
||||
// Executive meetings: sample data for today (idempotent per-date)
|
||||
const today = new Date().toISOString().slice(0, 10);
|
||||
const existingForToday = await db
|
||||
.select({ id: executiveMeetingsTable.id })
|
||||
.from(executiveMeetingsTable)
|
||||
.where(eq(executiveMeetingsTable.meetingDate, today));
|
||||
if (existingForToday.length === 0) {
|
||||
{
|
||||
const sampleMeetings: Array<{
|
||||
meeting: {
|
||||
dailyNumber: number;
|
||||
titleAr: string;
|
||||
titleEn: string;
|
||||
meetingDate: string;
|
||||
startTime: string;
|
||||
endTime: string;
|
||||
platform: "none" | "webex" | "teams" | "zoom" | "other";
|
||||
isHighlighted: number;
|
||||
status: string;
|
||||
};
|
||||
attendees: Array<{
|
||||
name: string;
|
||||
attendanceType: "internal" | "virtual" | "external";
|
||||
}>;
|
||||
}> = [
|
||||
{
|
||||
meeting: {
|
||||
dailyNumber: 1,
|
||||
titleAr: "اجتماع افتتاحي للمكتب التنفيذي",
|
||||
titleEn: "Executive Office Opening Meeting",
|
||||
meetingDate: today,
|
||||
startTime: "10:00",
|
||||
endTime: "10:30",
|
||||
platform: "none",
|
||||
isHighlighted: 0,
|
||||
status: "scheduled",
|
||||
},
|
||||
attendees: [
|
||||
{ name: "أ. سعد العتيبي", attendanceType: "internal" },
|
||||
{ name: "أ. خالد الشهري", attendanceType: "internal" },
|
||||
],
|
||||
},
|
||||
{
|
||||
meeting: {
|
||||
dailyNumber: 2,
|
||||
titleAr: "اجتماع بشأن خطة التحول الرقمي",
|
||||
titleEn: "Digital Transformation Plan Meeting",
|
||||
meetingDate: today,
|
||||
startTime: "11:00",
|
||||
endTime: "11:30",
|
||||
platform: "webex",
|
||||
isHighlighted: 0,
|
||||
status: "scheduled",
|
||||
},
|
||||
attendees: [
|
||||
{ name: "د. محمد الزهراني", attendanceType: "virtual" },
|
||||
{ name: "أ. عبدالعزيز القحطاني", attendanceType: "virtual" },
|
||||
{ name: "أ. ناصر الدوسري", attendanceType: "virtual" },
|
||||
{ name: "م. فهد المالكي", attendanceType: "virtual" },
|
||||
],
|
||||
},
|
||||
{
|
||||
meeting: {
|
||||
dailyNumber: 3,
|
||||
titleAr: "اجتماع تحضيري لاجتماع مجلس الإدارة",
|
||||
titleEn: "Board Meeting Preparation",
|
||||
meetingDate: today,
|
||||
startTime: "11:40",
|
||||
endTime: "12:10",
|
||||
platform: "none",
|
||||
isHighlighted: 0,
|
||||
status: "scheduled",
|
||||
},
|
||||
attendees: [
|
||||
{ name: "أ. تركي السبيعي", attendanceType: "internal" },
|
||||
{ name: "أ. ماجد الحربي", attendanceType: "internal" },
|
||||
{ name: "أ. عبدالله البقمي", attendanceType: "internal" },
|
||||
{ name: "أ. سلطان الغامدي", attendanceType: "internal" },
|
||||
],
|
||||
},
|
||||
{
|
||||
meeting: {
|
||||
dailyNumber: 4,
|
||||
titleAr: "اجتماع بشأن عرض الخطة الخاصة بالقطاعين",
|
||||
titleEn: "Two-Sector Plan Presentation",
|
||||
meetingDate: today,
|
||||
startTime: "13:00",
|
||||
endTime: "13:30",
|
||||
platform: "none",
|
||||
isHighlighted: 0,
|
||||
status: "scheduled",
|
||||
},
|
||||
attendees: [
|
||||
{ name: "أ. بدر العنزي", attendanceType: "internal" },
|
||||
{ name: "أ. هاني المطيري", attendanceType: "internal" },
|
||||
{ name: "أ. وليد الرشيدي", attendanceType: "internal" },
|
||||
{ name: "أ. يوسف الجهني", attendanceType: "internal" },
|
||||
{ name: "أ. عبدالرحمن الشمري", attendanceType: "internal" },
|
||||
],
|
||||
},
|
||||
{
|
||||
meeting: {
|
||||
dailyNumber: 5,
|
||||
titleAr: "اجتماع مع أ. عبدالله بشأن المتابعة",
|
||||
titleEn: "Follow-up Meeting with Mr. Abdullah",
|
||||
meetingDate: today,
|
||||
startTime: "13:30",
|
||||
endTime: "13:50",
|
||||
platform: "none",
|
||||
isHighlighted: 0,
|
||||
status: "scheduled",
|
||||
},
|
||||
attendees: [{ name: "أ. عبدالله الزهراني", attendanceType: "internal" }],
|
||||
},
|
||||
{
|
||||
meeting: {
|
||||
dailyNumber: 6,
|
||||
titleAr: "اجتماع دوري بشأن مواضيع مكتب الإدارة",
|
||||
titleEn: "Periodic Office Topics Meeting",
|
||||
meetingDate: today,
|
||||
startTime: "14:00",
|
||||
endTime: "14:30",
|
||||
platform: "none",
|
||||
isHighlighted: 0,
|
||||
status: "scheduled",
|
||||
},
|
||||
attendees: [
|
||||
{ name: "أ. مازن الفيفي", attendanceType: "internal" },
|
||||
{ name: "أ. سامي العسيري", attendanceType: "internal" },
|
||||
{ name: "أ. أحمد البلوي", attendanceType: "internal" },
|
||||
],
|
||||
},
|
||||
{
|
||||
meeting: {
|
||||
dailyNumber: 7,
|
||||
titleAr: "اجتماع بشأن إطار اعتماد البرامج",
|
||||
titleEn: "Program Accreditation Framework",
|
||||
meetingDate: today,
|
||||
startTime: "14:40",
|
||||
endTime: "15:10",
|
||||
platform: "none",
|
||||
isHighlighted: 0,
|
||||
status: "scheduled",
|
||||
},
|
||||
attendees: [
|
||||
{ name: "د. عبدالمجيد الحارثي", attendanceType: "internal" },
|
||||
{ name: "د. منصور القرني", attendanceType: "internal" },
|
||||
{ name: "أ. فيصل الزهراني", attendanceType: "internal" },
|
||||
],
|
||||
},
|
||||
{
|
||||
meeting: {
|
||||
dailyNumber: 8,
|
||||
titleAr: "اجتماع بشأن استراتيجية الموارد البشرية",
|
||||
titleEn: "HR Strategy Meeting",
|
||||
meetingDate: today,
|
||||
startTime: "15:30",
|
||||
endTime: "16:30",
|
||||
platform: "webex",
|
||||
isHighlighted: 1,
|
||||
status: "scheduled",
|
||||
},
|
||||
attendees: [
|
||||
{ name: "د. سعود الشهراني", attendanceType: "virtual" },
|
||||
{ name: "أ. عبدالإله الحربي", attendanceType: "virtual" },
|
||||
{ name: "أ. خالد العنزي", attendanceType: "virtual" },
|
||||
{ name: "أ. أحمد المالكي", attendanceType: "internal" },
|
||||
{ name: "أ. ناصر القحطاني", attendanceType: "internal" },
|
||||
{ name: "أ. سعيد الغامدي", attendanceType: "internal" },
|
||||
{ name: "أ. علي الزهراني", attendanceType: "internal" },
|
||||
{ name: "أ. محمد البقمي", attendanceType: "internal" },
|
||||
],
|
||||
},
|
||||
{
|
||||
meeting: {
|
||||
dailyNumber: 9,
|
||||
titleAr: "اجتماع بشأن متابعة المشاريع المشتركة",
|
||||
titleEn: "Joint Projects Follow-up",
|
||||
meetingDate: today,
|
||||
startTime: "16:40",
|
||||
endTime: "17:10",
|
||||
platform: "webex",
|
||||
isHighlighted: 0,
|
||||
status: "scheduled",
|
||||
},
|
||||
attendees: [
|
||||
{ name: "أ. يزيد العتيبي", attendanceType: "virtual" },
|
||||
{ name: "أ. تركي السهلي", attendanceType: "virtual" },
|
||||
{ name: "أ. عبدالله الزيد", attendanceType: "internal" },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
for (const { meeting, attendees } of sampleMeetings) {
|
||||
const [inserted] = await db
|
||||
.insert(executiveMeetingsTable)
|
||||
.values(meeting)
|
||||
.returning();
|
||||
if (!inserted) continue;
|
||||
await db.insert(executiveMeetingAttendeesTable).values(
|
||||
attendees.map((a, idx) => ({
|
||||
meetingId: inserted.id,
|
||||
name: a.name,
|
||||
attendanceType: a.attendanceType,
|
||||
sortOrder: idx,
|
||||
})),
|
||||
);
|
||||
}
|
||||
console.log("Executive Meetings sample data created for today");
|
||||
}
|
||||
} else {
|
||||
console.log("Executive Meetings sample data already exists for today, skipping");
|
||||
}
|
||||
|
||||
console.log("\n✅ Seeding complete!");
|
||||
console.log("\nDemo accounts:");
|
||||
console.log(" Admin: username=admin, password=admin123");
|
||||
|
||||
Reference in New Issue
Block a user