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"
/>