Skip to content

Commit

Permalink
feat(aih): add list type field & fix list saving
Browse files Browse the repository at this point in the history
  • Loading branch information
vojtaholik committed Jan 9, 2025
1 parent 424b2d5 commit 88bcfef
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,18 @@ import { z } from 'zod'
import { VideoResource } from '@coursebuilder/core/schemas/video-resource'
import {
Button,
FormControl,
FormDescription,
FormField,
FormItem,
FormLabel,
FormMessage,
Input,
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
Textarea,
} from '@coursebuilder/ui'
import { useSocket } from '@coursebuilder/ui/hooks/use-socket'
Expand Down Expand Up @@ -61,6 +67,31 @@ export const ListMetadataFormFields: React.FC<{
</FormItem>
)}
/>
<FormField
control={form.control}
name="fields.type"
render={({ field }) => {
return (
<FormItem className="px-5">
<FormLabel className="text-lg font-bold">Type</FormLabel>
<Select
onValueChange={field.onChange}
defaultValue={field.value || 'nextUp'}
>
<FormControl>
<SelectTrigger className="w-full">
<SelectValue placeholder="Select product type..." />
</SelectTrigger>
</FormControl>
<SelectContent>
<SelectItem value="nextUp">Next Up</SelectItem>
</SelectContent>
</Select>
<FormMessage />
</FormItem>
)
}}
/>
<FormField
control={form.control}
name="fields.description"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { env } from '@/env.mjs'
import { useIsMobile } from '@/hooks/use-is-mobile'
import { sendResourceChatMessage } from '@/lib/ai-chat-query'
import { List, ListSchema } from '@/lib/lists'
import { updateList } from '@/lib/lists-query'
import { Post, PostSchema } from '@/lib/posts'
import { autoUpdatePost, updatePost } from '@/lib/posts-query'
import type { Tag } from '@/lib/tags'
Expand Down Expand Up @@ -54,6 +55,7 @@ export function EditListForm({ list }: Omit<EditListFormProps, 'form'>) {
title: list.fields?.title,
body: list.fields?.body,
slug: list.fields?.slug,
type: list.fields?.type,
visibility: list.fields?.visibility || 'public',
state: list.fields?.state || 'draft',
description: list.fields?.description ?? '',
Expand All @@ -69,8 +71,8 @@ export function EditListForm({ list }: Omit<EditListFormProps, 'form'>) {
resource={list}
resourceSchema={ListSchema}
getResourcePath={(slug) => `/${slug}`}
updateResource={updatePost}
autoUpdateResource={autoUpdatePost}
updateResource={updateList}
// autoUpdateResource={autoUpdatePost}
form={form}
bodyPanelSlot={<ListResoucesEdit list={list} />}
availableWorkflows={[]}
Expand Down
52 changes: 51 additions & 1 deletion apps/ai-hero/src/lib/lists-query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { courseBuilderAdapter, db } from '@/db'
import { contentResource, contentResourceResource } from '@/db/schema'
import { getServerAuthSession } from '@/server/auth'
import { guid } from '@/utils/guid'
import { subject } from '@casl/ability'
import slugify from '@sindresorhus/slugify'
import { and, asc, desc, eq, or, sql } from 'drizzle-orm'
import { z } from 'zod'
Expand All @@ -14,7 +15,8 @@ import {
ContentResourceSchema,
} from '@coursebuilder/core/schemas'

import { ListSchema } from './lists'
import { ListSchema, type ListUpdate } from './lists'
import { upsertPostToTypeSense } from './typesense-query'

export async function createList(input: {
title: string
Expand Down Expand Up @@ -152,3 +154,51 @@ export async function removePostFromList({
),
)
}

export async function updateList(
input: ListUpdate,
action: 'save' | 'publish' | 'archive' | 'unpublish' = 'save',
revalidate = true,
) {
const { session, ability } = await getServerAuthSession()
const user = session?.user

const currentList = await getList(input.id)

if (!currentList) {
throw new Error(`Post with id ${input.id} not found.`)
}

if (!user || !ability.can(action, subject('Content', currentList))) {
throw new Error('Unauthorized')
}

let listSlug = currentList.fields.slug

if (
input.fields.title !== currentList.fields.title &&
input.fields.slug.includes('~')
) {
const splitSlug = currentList?.fields.slug.split('~') || ['', guid()]
listSlug = `${slugify(input.fields.title)}~${splitSlug[1] || guid()}`
} else if (input.fields.slug !== currentList.fields.slug) {
listSlug = input.fields.slug
}

try {
await upsertPostToTypeSense(currentList, action)
} catch (e) {
console.error('Failed to update post in Typesense', e)
}

revalidate && revalidateTag('lists')

return courseBuilderAdapter.updateContentResourceFields({
id: currentList.id,
fields: {
...currentList.fields,
...input.fields,
slug: listSlug,
},
})
}
20 changes: 20 additions & 0 deletions apps/ai-hero/src/lib/lists.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,15 @@ import { ContentResourceSchema } from '@coursebuilder/core/schemas'

import { PostSchema, PostStateSchema, PostVisibilitySchema } from './posts'

export const ListTypeSchema = z.enum(['nextUp'])

export const ListSchema = ContentResourceSchema.merge(
z.object({
fields: z.object({
title: z.string(),
description: z.string().optional(),
slug: z.string(),
type: ListTypeSchema.default('nextUp'),
body: z.string().nullable().optional(),
summary: z.string().optional().nullable(),
state: PostStateSchema.default('draft'),
Expand All @@ -22,3 +25,20 @@ export const ListSchema = ContentResourceSchema.merge(
)

export type List = z.infer<typeof ListSchema>

export const ListUpdateSchema = z.object({
id: z.string(),
fields: z.object({
title: z.string().min(2).max(90),
body: z.string().optional().nullable(),
slug: z.string(),
type: ListTypeSchema.default('nextUp'),
description: z.string().nullish(),
state: PostStateSchema.default('draft'),
visibility: PostVisibilitySchema.default('unlisted'),
github: z.string().nullish(),
}),
videoResourceId: z.string().optional().nullable(),
})

export type ListUpdate = z.infer<typeof ListUpdateSchema>

0 comments on commit 88bcfef

Please sign in to comment.