diff --git a/packages/backend/src/services/lessons.ts b/packages/backend/src/services/lessons.ts index b00584f..cc963a3 100644 --- a/packages/backend/src/services/lessons.ts +++ b/packages/backend/src/services/lessons.ts @@ -18,6 +18,10 @@ function rowToLesson(r: typeof lessons.$inferSelect): Lesson { description: r.description ?? null, position: r.position, bidirectional: r.bidirectional, + ownerId: r.ownerId ?? null, + visibility: r.visibility, + isCurated: r.isCurated, + sourceLessonId: r.sourceLessonId ?? null, createdAt: r.createdAt, updatedAt: r.updatedAt, }; diff --git a/packages/shared/src/schemas.ts b/packages/shared/src/schemas.ts index b0e86ed..b72e460 100644 --- a/packages/shared/src/schemas.ts +++ b/packages/shared/src/schemas.ts @@ -108,3 +108,22 @@ export type ChangePasswordInput = z.infer; export type AcceptInviteInput = z.infer; export type InviteUserInput = z.infer; export type AdminUserUpdateInput = z.infer; + +export const lessonVisibilityUpdateSchema = z.object({ + visibility: z.enum(['private', 'shared']), +}); + +export const adminLessonCuratedSchema = z.object({ + isCurated: z.boolean(), +}); + +export const marketplaceQuerySchema = z.object({ + q: z.string().trim().max(120).optional(), + curated: z.enum(['true', 'false']).optional(), + limit: z.coerce.number().int().min(1).max(100).optional(), + offset: z.coerce.number().int().min(0).optional(), +}); + +export type LessonVisibilityUpdateInput = z.infer; +export type AdminLessonCuratedInput = z.infer; +export type MarketplaceQuery = z.infer; diff --git a/packages/shared/src/types.ts b/packages/shared/src/types.ts index 7a69219..18a90bb 100644 --- a/packages/shared/src/types.ts +++ b/packages/shared/src/types.ts @@ -2,6 +2,8 @@ export type Direction = 'forward' | 'backward'; export type AttemptResult = 'correct' | 'incorrect'; export type SessionStatus = 'active' | 'completed' | 'abandoned'; +export type Visibility = 'private' | 'shared'; + export interface Lesson { id: number; parentId: number | null; @@ -9,6 +11,10 @@ export interface Lesson { description: string | null; position: number; bidirectional: boolean; + ownerId: number | null; + visibility: Visibility; + isCurated: boolean; + sourceLessonId: number | null; createdAt: number; updatedAt: number; } @@ -92,3 +98,28 @@ export interface PublicUser { displayName: string; role: Role; } + +export interface LessonAccess { + canEdit: boolean; + isOwner: boolean; + isSubscribed: boolean; +} + +export interface MarketplaceLesson { + id: number; + name: string; + description: string | null; + ownerDisplayName: string; + totalCards: number; + subscribersCount: number; + isCurated: boolean; + isFork: boolean; + createdAt: number; +} + +export interface SubscriptionEntry { + lessonId: number; + name: string; + ownerDisplayName: string; + subscribedAt: number; +}