Spaces:
Runtime error
Runtime error
| <script lang="ts"> | |
| import { getContext } from 'svelte'; | |
| const i18n = getContext('i18n'); | |
| import DOMPurify from 'dompurify'; | |
| import fileSaver from 'file-saver'; | |
| const { saveAs } = fileSaver; | |
| import { toast } from 'svelte-sonner'; | |
| import { selectedFolder } from '$lib/stores'; | |
| import { | |
| deleteFolderById, | |
| getFolderById, | |
| updateFolderById, | |
| createNewFolder | |
| } from '$lib/apis/folders'; | |
| import { getChatsByFolderId } from '$lib/apis/chats'; | |
| import FolderModal from '$lib/components/layout/Sidebar/Folders/FolderModal.svelte'; | |
| import Folder from '$lib/components/icons/Folder.svelte'; | |
| import XMark from '$lib/components/icons/XMark.svelte'; | |
| import FolderMenu from '$lib/components/layout/Sidebar/Folders/FolderMenu.svelte'; | |
| import EllipsisHorizontal from '$lib/components/icons/EllipsisHorizontal.svelte'; | |
| import DeleteConfirmDialog from '$lib/components/common/ConfirmDialog.svelte'; | |
| import Emoji from '$lib/components/common/Emoji.svelte'; | |
| import EmojiPicker from '$lib/components/common/EmojiPicker.svelte'; | |
| export let folder = null; | |
| export let onUpdate: Function = (folderId) => {}; | |
| export let onDelete: Function = (folderId) => {}; | |
| let showFolderModal = false; | |
| let showCreateSubFolderModal = false; | |
| let showDeleteConfirm = false; | |
| let deleteFolderContents = true; | |
| const updateHandler = async ({ name, meta, data }) => { | |
| if (name === '') { | |
| toast.error($i18n.t('Folder name cannot be empty.')); | |
| return; | |
| } | |
| const currentName = folder.name; | |
| name = name.trim(); | |
| folder.name = name; | |
| const res = await updateFolderById(localStorage.token, folder.id, { | |
| name, | |
| ...(meta ? { meta } : {}), | |
| ...(data ? { data } : {}) | |
| }).catch((error) => { | |
| toast.error(`${error}`); | |
| folder.name = currentName; | |
| return null; | |
| }); | |
| if (res) { | |
| folder.name = name; | |
| if (data) { | |
| folder.data = data; | |
| } | |
| toast.success($i18n.t('Folder updated successfully')); | |
| const _folder = await getFolderById(localStorage.token, folder.id).catch((error) => { | |
| toast.error(`${error}`); | |
| return null; | |
| }); | |
| await selectedFolder.set(_folder); | |
| onUpdate(_folder); | |
| } | |
| }; | |
| const updateIconHandler = async (iconName) => { | |
| const res = await updateFolderById(localStorage.token, folder.id, { | |
| meta: { | |
| icon: iconName ?? '' | |
| } | |
| }).catch((error) => { | |
| toast.error(`${error}`); | |
| return null; | |
| }); | |
| if (res) { | |
| folder.meta = { ...folder.meta, icon: iconName ?? '' }; | |
| toast.success($i18n.t('Folder updated successfully')); | |
| const _folder = await getFolderById(localStorage.token, folder.id).catch((error) => { | |
| toast.error(`${error}`); | |
| return null; | |
| }); | |
| await selectedFolder.set(_folder); | |
| onUpdate(_folder); | |
| } | |
| }; | |
| const deleteHandler = async () => { | |
| const res = await deleteFolderById(localStorage.token, folder.id, deleteFolderContents).catch( | |
| (error) => { | |
| toast.error(`${error}`); | |
| return null; | |
| } | |
| ); | |
| if (res) { | |
| toast.success($i18n.t('Folder deleted successfully')); | |
| onDelete(folder); | |
| } | |
| }; | |
| const exportHandler = async () => { | |
| const chats = await getChatsByFolderId(localStorage.token, folder.id).catch((error) => { | |
| toast.error(`${error}`); | |
| return null; | |
| }); | |
| if (!chats) { | |
| return; | |
| } | |
| const blob = new Blob([JSON.stringify(chats)], { | |
| type: 'application/json' | |
| }); | |
| saveAs(blob, `folder-${folder.name}-export-${Date.now()}.json`); | |
| }; | |
| const createSubFolderHandler = async ({ name, meta, data, parent_id }) => { | |
| if (name === '') { | |
| toast.error($i18n.t('Folder name cannot be empty.')); | |
| return; | |
| } | |
| name = name.trim(); | |
| const res = await createNewFolder(localStorage.token, { | |
| name, | |
| data, | |
| meta, | |
| parent_id | |
| }).catch((error) => { | |
| toast.error(`${error}`); | |
| return null; | |
| }); | |
| if (res) { | |
| toast.success($i18n.t('Folder created successfully')); | |
| onUpdate(); | |
| } | |
| }; | |
| </script> | |
| {#if folder} | |
| <FolderModal | |
| bind:show={showFolderModal} | |
| edit={true} | |
| folderId={folder.id} | |
| onSubmit={updateHandler} | |
| /> | |
| <FolderModal | |
| bind:show={showCreateSubFolderModal} | |
| parentId={folder.id} | |
| onSubmit={createSubFolderHandler} | |
| /> | |
| <DeleteConfirmDialog | |
| bind:show={showDeleteConfirm} | |
| title={$i18n.t('Delete folder?')} | |
| on:confirm={() => { | |
| deleteHandler(); | |
| }} | |
| > | |
| <div class=" text-sm text-gray-700 dark:text-gray-300 flex-1 line-clamp-3 mb-2"> | |
| <!-- {$i18n.t('This will delete <strong>{{NAME}}</strong> and <strong>all its contents</strong>.', { | |
| NAME: folder.name | |
| })} --> | |
| {$i18n.t(`Are you sure you want to delete "{{NAME}}"?`, { | |
| NAME: folder.name | |
| })} | |
| </div> | |
| <div class="flex items-center gap-1.5"> | |
| <input type="checkbox" bind:checked={deleteFolderContents} /> | |
| <div class="text-xs text-gray-500"> | |
| {$i18n.t('Delete all contents inside this folder')} | |
| </div> | |
| </div> | |
| </DeleteConfirmDialog> | |
| <div class="mb-3 px-6 @md:max-w-3xl justify-between w-full flex relative group items-center"> | |
| <div class="text-center flex gap-3.5 items-center"> | |
| <EmojiPicker | |
| onClose={() => {}} | |
| selected={folder?.meta?.icon ?? null} | |
| onSubmit={(name) => { | |
| console.log(name); | |
| updateIconHandler(name); | |
| }} | |
| > | |
| <button | |
| aria-label={$i18n.t('Change folder icon')} | |
| class=" rounded-full bg-gray-50 dark:bg-gray-800 size-11 flex justify-center items-center" | |
| > | |
| {#if folder?.meta?.icon} | |
| <Emoji className="size-6" shortCode={folder.meta.icon} /> | |
| {:else} | |
| <Folder className="size-4.5" strokeWidth="2" /> | |
| {/if} | |
| </button> | |
| </EmojiPicker> | |
| <div class="text-3xl line-clamp-1"> | |
| {folder.name} | |
| </div> | |
| </div> | |
| <div class="flex items-center translate-x-2.5"> | |
| <FolderMenu | |
| align="end" | |
| onEdit={() => { | |
| showFolderModal = true; | |
| }} | |
| onDelete={() => { | |
| showDeleteConfirm = true; | |
| }} | |
| onExport={() => { | |
| exportHandler(); | |
| }} | |
| onCreateSubFolder={() => { | |
| showCreateSubFolderModal = true; | |
| }} | |
| > | |
| <button | |
| class="p-1.5 dark:hover:bg-gray-850 rounded-full touch-auto" | |
| aria-label={$i18n.t('Folder options')} | |
| on:click={(e) => {}} | |
| > | |
| <EllipsisHorizontal className="size-4" strokeWidth="2.5" /> | |
| </button> | |
| </FolderMenu> | |
| </div> | |
| </div> | |
| {/if} | |