feat: widgets and ai chat

This commit is contained in:
Rotimi Best
2026-04-27 11:40:38 +01:00
parent ae1801f85f
commit 5717dd8004
391 changed files with 28177 additions and 22467 deletions
+30 -1
View File
@@ -6,15 +6,17 @@ interface SeedCourse {
mvcGroupId: string;
reactGroupId: string;
pandasGroupId: string;
earlyAdopterGroupId: string;
}
export async function seedCourses({ mvcGroupId, reactGroupId, pandasGroupId }: SeedCourse) {
export async function seedCourses({ mvcGroupId, reactGroupId, pandasGroupId, earlyAdopterGroupId }: SeedCourse) {
const existingCourses = await db.select().from(course);
const existingCourseIds = existingCourses.map((c) => c.id);
const mvcCourseId = '98e6e798-f0bd-4f9d-a6f5-ce0816a4f97e';
const reactCourseId = '16e3bc8d-5d1b-4708-988e-93abae288ccf';
const pandasCourseId = 'f0a85d18-aff4-412f-b8e6-3b34ef098dce';
const earlyAdopterCourseId = '9bd496cc-c494-4a7e-e12c-6baeef246f8b';
const coursesToInsert: TNewCourse[] = [
{
@@ -98,6 +100,33 @@ export async function seedCourses({ mvcGroupId, reactGroupId, pandasGroupId }: S
theme: 'professional'
},
status: 'ACTIVE'
},
{
id: earlyAdopterCourseId,
title: 'Product Management Fundamentals',
description:
'A practical introduction to product management covering roadmaps, prioritization frameworks, user research, and cross-functional collaboration skills needed to ship great products.',
overview: 'Welcome to Product Management Fundamentals 🚀',
groupId: earlyAdopterGroupId,
isTemplate: false,
logo: '',
slug: 'product-management-fundamentals',
metadata: {
goals: '',
grading: false,
description: '',
requirements: '',
lessonDownload: false,
allowNewStudent: true
},
cost: 0,
currency: 'NGN',
isPublished: true,
certificate: {
isDownloadable: false,
theme: 'professional'
},
status: 'ACTIVE'
}
].filter((c) => !existingCourseIds.includes(c.id));
+17 -1
View File
@@ -5,9 +5,18 @@ interface SeedGroup {
reactGroupId: string;
pandasGroupId: string;
testOrgId: string;
earlyAdopterGroupId: string;
earlyAdopterOrgId: string;
}
export async function seedGroup({ mvcGroupId, reactGroupId, pandasGroupId, testOrgId }: SeedGroup) {
export async function seedGroup({
mvcGroupId,
reactGroupId,
pandasGroupId,
testOrgId,
earlyAdopterGroupId,
earlyAdopterOrgId
}: SeedGroup) {
const existingGroups = await db.select().from(group);
const existingGroupIds = existingGroups.map((g) => g.id);
@@ -32,6 +41,13 @@ export async function seedGroup({ mvcGroupId, reactGroupId, pandasGroupId, testO
description:
'Unlock the power of data with our "Data Science with Python and Pandas" course. Dive into Python programming fundamentals and then journey into the world of Pandas for efficient data manipulation and analysis.',
organizationId: testOrgId
},
{
id: earlyAdopterGroupId,
name: 'Product Management Fundamentals',
description:
'A practical introduction to product management covering roadmaps, prioritization frameworks, user research, and cross-functional collaboration skills needed to ship great products.',
organizationId: earlyAdopterOrgId
}
].filter((g) => !existingGroupIds.includes(g.id));
+18 -1
View File
@@ -6,6 +6,9 @@ interface SeedGroupmember {
pandasGroupId: string;
adminUserId: string;
studentUserId: string;
earlyAdopterGroupId: string;
earlyAdopterAdminUserId: string;
earlyAdopterStudentUserId: string;
}
export async function seedGroupmembers({
@@ -13,7 +16,10 @@ export async function seedGroupmembers({
reactGroupId,
pandasGroupId,
adminUserId,
studentUserId
studentUserId,
earlyAdopterGroupId,
earlyAdopterAdminUserId,
earlyAdopterStudentUserId
}: SeedGroupmember) {
const existingGroupMembers = await db.select().from(groupmember);
const existingGroupMemberKeys = existingGroupMembers.map((gm) => `${gm.groupId}-${gm.profileId || gm.email}`);
@@ -41,6 +47,17 @@ export async function seedGroupmembers({
groupId: pandasGroupId,
roleId: 3, // STUDENT
profileId: studentUserId
},
{
groupId: earlyAdopterGroupId,
roleId: 2, // TUTOR
profileId: earlyAdopterAdminUserId,
email: 'early-adopter@test.com'
},
{
groupId: earlyAdopterGroupId,
roleId: 3, // STUDENT
profileId: earlyAdopterStudentUserId
}
].filter((gm) => !existingGroupMemberKeys.includes(`${gm.groupId}-${gm.profileId || gm.email}`));
+22 -1
View File
@@ -1,6 +1,14 @@
import { db, organization } from '@db/drizzle';
export async function seedOrganization({ testOrgId, enterpriseOrgId }: { testOrgId: string; enterpriseOrgId: string }) {
export async function seedOrganization({
testOrgId,
enterpriseOrgId,
earlyAdopterOrgId
}: {
testOrgId: string;
enterpriseOrgId: string;
earlyAdopterOrgId: string;
}) {
const existingOrgs = await db.select().from(organization);
const existingOrgIds = existingOrgs.map((o) => o.id);
@@ -30,6 +38,19 @@ export async function seedOrganization({ testOrgId, enterpriseOrgId }: { testOrg
course: { grading: true, newsfeed: true },
dashboard: { exercise: true, community: true, bannerText: '', bannerImage: '' }
}
},
{
id: earlyAdopterOrgId,
name: 'Skillshare Test',
siteName: 'skillshare-test',
settings: {},
landingpage: {},
theme: '',
customization: {
apps: { poll: true, comments: true },
course: { grading: true, newsfeed: true },
dashboard: { exercise: true, community: true, bannerText: '', bannerImage: '' }
}
}
].filter((o) => !existingOrgIds.includes(o.id));
@@ -26,3 +26,30 @@ export async function seedEnterpriseOrganizationPlan({ enterpriseOrgId }: { ente
});
console.log(' ✓ Inserted enterprise organization plan');
}
export async function seedEarlyAdopterOrganizationPlan({ earlyAdopterOrgId }: { earlyAdopterOrgId: string }) {
const existing = await db
.select()
.from(organizationPlan)
.where(
and(
eq(organizationPlan.orgId, earlyAdopterOrgId),
eq(organizationPlan.planName, 'EARLY_ADOPTER'),
eq(organizationPlan.isActive, true)
)
);
if (existing.length > 0) {
console.log(' ✓ Early adopter organization plan already exists, skipping');
return;
}
await db.insert(organizationPlan).values({
orgId: earlyAdopterOrgId,
planName: 'EARLY_ADOPTER',
isActive: true,
subscriptionId: 'seed-skillshare-test-early-adopter',
provider: 'seed'
});
console.log(' ✓ Inserted early adopter organization plan');
}
@@ -7,6 +7,9 @@ interface SeedOrganizationMember {
enterpriseOrgId: string;
enterpriseAdminUserId: string;
enterpriseStudentUserId: string;
earlyAdopterOrgId: string;
earlyAdopterAdminUserId: string;
earlyAdopterStudentUserId: string;
}
export async function seedOrganizationMember({
@@ -15,7 +18,10 @@ export async function seedOrganizationMember({
studentUserId,
enterpriseOrgId,
enterpriseAdminUserId,
enterpriseStudentUserId
enterpriseStudentUserId,
earlyAdopterOrgId,
earlyAdopterAdminUserId,
earlyAdopterStudentUserId
}: SeedOrganizationMember) {
const existingOrgMembers = await db.select().from(organizationmember);
const existingOrgMemberKeys = existingOrgMembers.map((om) => `${om.organizationId}-${om.profileId}`);
@@ -44,6 +50,18 @@ export async function seedOrganizationMember({
roleId: 3, // STUDENT
profileId: enterpriseStudentUserId,
verified: false
},
{
organizationId: earlyAdopterOrgId,
roleId: 1, // ADMIN
profileId: earlyAdopterAdminUserId,
verified: false
},
{
organizationId: earlyAdopterOrgId,
roleId: 3, // STUDENT
profileId: earlyAdopterStudentUserId,
verified: false
}
].filter((om) => !existingOrgMemberKeys.includes(`${om.organizationId}-${om.profileId}`));