'use client' import type { MouseEventHandler } from 'react' import { useCallback, useEffect, useRef, useState } from 'react' import useSWR from 'swr' import classNames from 'classnames' import { useRouter } from 'next/navigation' import { useContext, useContextSelector } from 'use-context-selector' import { useTranslation } from 'react-i18next' import style from '../list.module.css' import AppModeLabel from './AppModeLabel' import Button from '@/app/components/base/button' import Dialog from '@/app/components/base/dialog' import type { AppMode } from '@/types/app' import { ToastContext } from '@/app/components/base/toast' import { createApp, fetchAppTemplates } from '@/service/apps' import AppIcon from '@/app/components/base/app-icon' import AppsContext from '@/context/app-context' import EmojiPicker from '@/app/components/base/emoji-picker' type NewAppDialogProps = { show: boolean onSuccess?: () => void onClose?: () => void } const NewAppDialog = ({ show, onSuccess, onClose }: NewAppDialogProps) => { const router = useRouter() const { notify } = useContext(ToastContext) const { t } = useTranslation() const nameInputRef = useRef(null) const [newAppMode, setNewAppMode] = useState() const [isWithTemplate, setIsWithTemplate] = useState(false) const [selectedTemplateIndex, setSelectedTemplateIndex] = useState(-1) // Emoji Picker const [showEmojiPicker, setShowEmojiPicker] = useState(false) const [emoji, setEmoji] = useState({ icon: '🤖', icon_background: '#FFEAD5' }) const mutateApps = useContextSelector(AppsContext, state => state.mutateApps) const { data: templates, mutate } = useSWR({ url: '/app-templates' }, fetchAppTemplates) const mutateTemplates = useCallback( () => mutate(), [], ) useEffect(() => { if (show) { mutateTemplates() setIsWithTemplate(false) } }, [mutateTemplates, show]) const isCreatingRef = useRef(false) const onCreate: MouseEventHandler = useCallback(async () => { const name = nameInputRef.current?.value if (!name) { notify({ type: 'error', message: t('app.newApp.nameNotEmpty') }) return } if (!templates || (isWithTemplate && !(selectedTemplateIndex > -1))) { notify({ type: 'error', message: t('app.newApp.appTemplateNotSelected') }) return } if (!isWithTemplate && !newAppMode) { notify({ type: 'error', message: t('app.newApp.appTypeRequired') }) return } if (isCreatingRef.current) return isCreatingRef.current = true try { const app = await createApp({ name, icon: emoji.icon, icon_background: emoji.icon_background, mode: isWithTemplate ? templates.data[selectedTemplateIndex].mode : newAppMode!, config: isWithTemplate ? templates.data[selectedTemplateIndex].model_config : undefined, }) if (onSuccess) onSuccess() if (onClose) onClose() notify({ type: 'success', message: t('app.newApp.appCreated') }) mutateApps() router.push(`/app/${app.id}/overview`) } catch (e) { notify({ type: 'error', message: t('app.newApp.appCreateFailed') }) } isCreatingRef.current = false }, [isWithTemplate, newAppMode, notify, router, templates, selectedTemplateIndex, emoji]) return <> {showEmojiPicker && { setEmoji({ icon, icon_background }) setShowEmojiPicker(false) }} onClose={() => { setEmoji({ icon: '🤖', icon_background: '#FFEAD5' }) setShowEmojiPicker(false) }} />} } >

{t('app.newApp.captionName')}

{ setShowEmojiPicker(true) }} className='cursor-pointer' icon={emoji.icon} background={emoji.icon_background} />

{t('app.newApp.captionAppType')}

{isWithTemplate && ( <> setIsWithTemplate(false)} > {t('app.newApp.hideTemplates')} )}
{isWithTemplate ? (
    {templates?.data?.map((template, index) => (
  • setSelectedTemplateIndex(index)} >
    {template.name}
    {template.model_config?.pre_prompt}
    {/* */}
  • ))}
) : ( <>
setIsWithTemplate(true)} > {t('app.newApp.showTemplates')}
)}
} export default NewAppDialog