AppCard.tsx 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. 'use client'
  2. import { useContext, useContextSelector } from 'use-context-selector'
  3. import Link from 'next/link'
  4. import type { MouseEventHandler } from 'react'
  5. import { useCallback, useState } from 'react'
  6. import { useTranslation } from 'react-i18next'
  7. import style from '../list.module.css'
  8. import AppModeLabel from './AppModeLabel'
  9. import type { App } from '@/types/app'
  10. import Confirm from '@/app/components/base/confirm'
  11. import { ToastContext } from '@/app/components/base/toast'
  12. import { deleteApp } from '@/service/apps'
  13. import AppIcon from '@/app/components/base/app-icon'
  14. import AppsContext from '@/context/app-context'
  15. export type AppCardProps = {
  16. app: App
  17. onDelete?: () => void
  18. }
  19. const AppCard = ({
  20. app,
  21. onDelete,
  22. }: AppCardProps) => {
  23. const { t } = useTranslation()
  24. const { notify } = useContext(ToastContext)
  25. const mutateApps = useContextSelector(AppsContext, state => state.mutateApps)
  26. const [showConfirmDelete, setShowConfirmDelete] = useState(false)
  27. const onDeleteClick: MouseEventHandler = useCallback((e) => {
  28. e.preventDefault()
  29. setShowConfirmDelete(true)
  30. }, [])
  31. const onConfirmDelete = useCallback(async () => {
  32. try {
  33. await deleteApp(app.id)
  34. notify({ type: 'success', message: t('app.appDeleted') })
  35. if (onDelete)
  36. onDelete()
  37. mutateApps()
  38. }
  39. catch (e: any) {
  40. notify({ type: 'error', message: `${t('app.appDeleteFailed')}${'message' in e ? `: ${e.message}` : ''}` })
  41. }
  42. setShowConfirmDelete(false)
  43. }, [app.id])
  44. return (
  45. <>
  46. <Link href={`/app/${app.id}/overview`} className={style.listItem}>
  47. <div className={style.listItemTitle}>
  48. <AppIcon size='small' icon={app.icon} background={app.icon_background} />
  49. <div className={style.listItemHeading}>
  50. <div className={style.listItemHeadingContent}>{app.name}</div>
  51. </div>
  52. <span className={style.deleteAppIcon} onClick={onDeleteClick} />
  53. </div>
  54. <div className={style.listItemDescription}>{app.model_config?.pre_prompt}</div>
  55. <div className={style.listItemFooter}>
  56. <AppModeLabel mode={app.mode} />
  57. </div>
  58. {showConfirmDelete && (
  59. <Confirm
  60. title={t('app.deleteAppConfirmTitle')}
  61. content={t('app.deleteAppConfirmContent')}
  62. isShow={showConfirmDelete}
  63. onClose={() => setShowConfirmDelete(false)}
  64. onConfirm={onConfirmDelete}
  65. onCancel={() => setShowConfirmDelete(false)}
  66. />
  67. )}
  68. </Link>
  69. </>
  70. )
  71. }
  72. export default AppCard