From d5cb337d5ec6b28bb3be3fd96540ea261bf5c5d1 Mon Sep 17 00:00:00 2001 From: Tanmay Deep Sharma <32020192+tds-1@users.noreply.github.com> Date: Thu, 10 Jul 2025 13:52:53 +0700 Subject: [PATCH] fix review changes --- .../captain/assistant/DocumentCard.vue | 3 +- .../document/CreateDocumentDialog.vue | 36 ++-- .../pageComponents/document/DocumentForm.vue | 169 +++++++++--------- .../components-next/fileUpload/FileUpload.vue | 76 +++----- .../i18n/locale/en/integrations.json | 24 ++- .../dashboard/store/captain/document.js | 34 +++- 6 files changed, 180 insertions(+), 162 deletions(-) diff --git a/app/javascript/dashboard/components-next/captain/assistant/DocumentCard.vue b/app/javascript/dashboard/components-next/captain/assistant/DocumentCard.vue index d0e85d246..11830c5d1 100644 --- a/app/javascript/dashboard/components-next/captain/assistant/DocumentCard.vue +++ b/app/javascript/dashboard/components-next/captain/assistant/DocumentCard.vue @@ -8,6 +8,7 @@ import { usePolicy } from 'dashboard/composables/usePolicy'; import CardLayout from 'dashboard/components-next/CardLayout.vue'; import DropdownMenu from 'dashboard/components-next/dropdown-menu/DropdownMenu.vue'; import Button from 'dashboard/components-next/button/Button.vue'; +import Icon from 'dashboard/components-next/icon/Icon.vue'; const props = defineProps({ id: { @@ -129,7 +130,7 @@ const handleAction = ({ action, value }) => { rel="noopener noreferrer" class="text-n-slate-11 text-sm truncate flex justify-start flex-1 items-center gap-1 hover:text-n-slate-12 transition-colors" > - + {{ displayLink }}
diff --git a/app/javascript/dashboard/components-next/captain/pageComponents/document/CreateDocumentDialog.vue b/app/javascript/dashboard/components-next/captain/pageComponents/document/CreateDocumentDialog.vue index 995453ae6..00b1e9f8e 100644 --- a/app/javascript/dashboard/components-next/captain/pageComponents/document/CreateDocumentDialog.vue +++ b/app/javascript/dashboard/components-next/captain/pageComponents/document/CreateDocumentDialog.vue @@ -2,43 +2,41 @@ import { ref } from 'vue'; import { useStore } from 'dashboard/composables/store'; import { useAlert } from 'dashboard/composables'; +import { useI18n } from 'vue-i18n'; import Dialog from 'dashboard/components-next/dialog/Dialog.vue'; import DocumentForm from './DocumentForm.vue'; const emit = defineEmits(['close', 'success']); + +// Constants +const DOCUMENT_TYPE = { + PDF: 'pdf', + URL: 'url', +}; + const store = useStore(); +const { t } = useI18n(); const dialogRef = ref(null); const documentForm = ref(null); const handleSubmit = async newDocument => { try { - if (newDocument.type === 'pdf') { - // Handle PDF upload - const formData = new FormData(); - formData.append('pdf_document', newDocument.pdf_document); - formData.append('assistant_id', newDocument.assistant_id); + await store.dispatch('captainDocuments/createDocument', newDocument); - await store.dispatch('captainDocuments/uploadPdf', formData); - useAlert('PDF uploaded successfully! Processing will begin shortly.'); - } else { - // Handle URL creation - await store.dispatch('captainDocuments/create', { - document: { - external_link: newDocument.external_link, - assistant_id: newDocument.assistant_id, - }, - }); - useAlert('Document created successfully!'); - } + // Show appropriate success message based on document type + const successMessage = + newDocument.type === DOCUMENT_TYPE.PDF + ? t('CAPTAIN.DOCUMENTS.CREATE.FORM.PDF_UPLOAD.SUCCESS_MESSAGE') + : t('CAPTAIN.DOCUMENTS.CREATE.SUCCESS_MESSAGE'); - // Emit success event to refresh the list + useAlert(successMessage); emit('success'); dialogRef.value.close(); } catch (error) { const errorMessage = error?.response?.data?.message || - 'Failed to create document. Please try again.'; + t('CAPTAIN.DOCUMENTS.CREATE.ERROR_MESSAGE'); useAlert(errorMessage); } }; diff --git a/app/javascript/dashboard/components-next/captain/pageComponents/document/DocumentForm.vue b/app/javascript/dashboard/components-next/captain/pageComponents/document/DocumentForm.vue index 58d5621c5..ddea6ad10 100644 --- a/app/javascript/dashboard/components-next/captain/pageComponents/document/DocumentForm.vue +++ b/app/javascript/dashboard/components-next/captain/pageComponents/document/DocumentForm.vue @@ -3,13 +3,41 @@ import { reactive, computed, ref } from 'vue'; import { useVuelidate } from '@vuelidate/core'; import { required, minLength, url } from '@vuelidate/validators'; import { useMapGetter } from 'dashboard/composables/store'; +import { useI18n } from 'vue-i18n'; +import { formatBytes } from 'shared/helpers/FileHelper'; import Input from 'dashboard/components-next/input/Input.vue'; import Button from 'dashboard/components-next/button/Button.vue'; import ComboBox from 'dashboard/components-next/combobox/ComboBox.vue'; import FileUpload from 'dashboard/components-next/fileUpload/FileUpload.vue'; +import Icon from 'dashboard/components-next/icon/Icon.vue'; const emit = defineEmits(['submit', 'cancel']); +const { t } = useI18n(); + +// Constants +const SOURCE_TYPE = { + URL: 'url', + PDF: 'pdf', +}; + +const MESSAGE_TYPE = { + ERROR: 'error', + INFO: 'info', +}; + +const DOCUMENT_TYPE = { + URL: 'url', + PDF: 'pdf', +}; + +const FIELD_NAME = { + URL: 'url', + ASSISTANT_ID: 'assistantId', +}; + +const FILE_ACCEPT_TYPE = 'application/pdf'; +const MAX_FILE_SIZE_MB = 25; const formState = { uiFlags: useMapGetter('captainDocuments/getUIFlags'), @@ -20,7 +48,7 @@ const initialState = { url: '', assistantId: null, selectedFile: null, - sourceType: 'url', // 'url' or 'pdf' + sourceType: SOURCE_TYPE.URL, }; const state = reactive({ ...initialState }); @@ -31,7 +59,7 @@ const validationRules = computed(() => { assistantId: { required }, }; - if (state.sourceType === 'url') { + if (state.sourceType === SOURCE_TYPE.URL) { rules.url = { required, url, minLength: minLength(1) }; } @@ -49,28 +77,39 @@ const v$ = useVuelidate(validationRules, state); const isLoading = computed(() => formState.uiFlags.value.creatingItem); +const formattedFileSize = computed(() => { + if (!state.selectedFile) return ''; + return formatBytes(state.selectedFile.size); +}); + const getErrorMessage = (field, errorMessage) => { return v$.value[field]?.$error ? errorMessage : ''; }; const formErrors = computed(() => ({ - url: getErrorMessage('url', 'Please enter a valid URL'), - assistantId: getErrorMessage('assistantId', 'Please select an assistant'), + url: getErrorMessage( + FIELD_NAME.URL, + t('CAPTAIN.DOCUMENTS.CREATE.FORM.URL.ERROR') + ), + assistantId: getErrorMessage( + FIELD_NAME.ASSISTANT_ID, + t('CAPTAIN.DOCUMENTS.CREATE.FORM.ASSISTANT.ERROR') + ), })); const handleCancel = () => emit('cancel'); const prepareDocumentDetails = () => { - if (state.sourceType === 'pdf') { + if (state.sourceType === SOURCE_TYPE.PDF) { return { - type: 'pdf', + type: DOCUMENT_TYPE.PDF, pdf_document: state.selectedFile, assistant_id: state.assistantId, }; } return { - type: 'url', + type: DOCUMENT_TYPE.URL, external_link: state.url, assistant_id: state.assistantId, }; @@ -86,8 +125,8 @@ const handleSubmit = async () => { } // For PDF uploads, check if file is selected - if (state.sourceType === 'pdf' && !state.selectedFile) { - uploadError.value = 'Please select a PDF file to upload.'; + if (state.sourceType === SOURCE_TYPE.PDF && !state.selectedFile) { + uploadError.value = t('CAPTAIN.DOCUMENTS.CREATE.FORM.PDF_UPLOAD.ERROR'); return; } @@ -130,26 +169,15 @@ const handleSourceTypeChange = type => { type="button" class="flex-1 p-3 rounded-lg bg-n-alpha-2 hover:border-n-slate-7 transition-colors focus:outline-none" :class="{ - 'ring-2 ring-woot-500 text-woot-500 border-0': - state.sourceType === 'url', + 'ring-2 ring-n-brand text-n-brand border-0': + state.sourceType === SOURCE_TYPE.URL, 'border-2 border-n-slate-7 text-n-slate-11': - state.sourceType !== 'url', + state.sourceType !== SOURCE_TYPE.URL, }" - @click="handleSourceTypeChange('url')" + @click="handleSourceTypeChange(SOURCE_TYPE.URL)" >
- - - + {{ $t('CAPTAIN.DOCUMENTS.CREATE.FORM.SOURCE_TYPE.WEBSITE_URL') }} @@ -159,26 +187,15 @@ const handleSourceTypeChange = type => { type="button" class="flex-1 p-3 rounded-lg bg-n-alpha-2 hover:border-n-slate-7 transition-colors focus:outline-none" :class="{ - 'ring-2 ring-woot-500 text-woot-500 border-0': - state.sourceType === 'pdf', + 'ring-2 ring-n-brand text-n-brand border-0': + state.sourceType === SOURCE_TYPE.PDF, 'border-2 border-n-slate-7 text-n-slate-11': - state.sourceType !== 'pdf', + state.sourceType !== SOURCE_TYPE.PDF, }" - @click="handleSourceTypeChange('pdf')" + @click="handleSourceTypeChange(SOURCE_TYPE.PDF)" >
- - - + {{ $t('CAPTAIN.DOCUMENTS.CREATE.FORM.SOURCE_TYPE.PDF_UPLOAD') }} @@ -188,18 +205,21 @@ const handleSourceTypeChange = type => {
-
+
-
+
@@ -207,11 +227,15 @@ const handleSourceTypeChange = type => {
@@ -221,29 +245,13 @@ const handleSourceTypeChange = type => {
- - - +

{{ state.selectedFile.name }}

- {{ - Math.round((state.selectedFile.size / 1024 / 1024) * 100) / - 100 - }} - {{ $t('GENERAL.FILE_SIZE.MB') }} + {{ formattedFileSize }}

@@ -252,24 +260,13 @@ const handleSourceTypeChange = type => { class="p-1 rounded hover:bg-n-alpha-3 text-n-slate-8 hover:text-n-slate-10" @click="clearSelectedFile" > - - - +
-

{{ uploadError }}

+

{{ uploadError }}

@@ -282,7 +279,7 @@ const handleSourceTypeChange = type => { v-model="state.assistantId" :options="assistantList" :has-error="!!formErrors.assistantId" - placeholder="Choose an assistant" + :placeholder="t('CAPTAIN.DOCUMENTS.CREATE.FORM.ASSISTANT.PLACEHOLDER')" class="[&>div>button]:bg-n-alpha-black2 [&>div>button:not(.focused)]:dark:outline-n-weak [&>div>button:not(.focused)]:hover:!outline-n-slate-6" :message="formErrors.assistantId" /> @@ -294,13 +291,13 @@ const handleSourceTypeChange = type => { type="button" variant="faded" color="slate" - label="Cancel" - class="w-full bg-n-alpha-2 n-blue-text hover:bg-n-alpha-3" + :label="t('CAPTAIN.DOCUMENTS.CREATE.FORM.ACTIONS.CANCEL')" + class="w-full bg-n-alpha-2 text-n-blue-11 hover:bg-n-alpha-3" @click="handleCancel" />