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.
This commit is contained in:
Riyadh
2026-04-27 12:05:40 +00:00
parent 2827e092b3
commit 1b96b6528d
10 changed files with 1055 additions and 0 deletions
+265
View File
@@ -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");