diff --git a/resources/js/forms/classic/interactions/ButtonAction.vue b/resources/js/forms/classic/interactions/ButtonAction.vue
index bf0257cc..738f9589 100644
--- a/resources/js/forms/classic/interactions/ButtonAction.vue
+++ b/resources/js/forms/classic/interactions/ButtonAction.vue
@@ -29,9 +29,7 @@
@keydown.enter="stopEditing($event, true)"
type="text"
:placeholder="
- isChecked && !otherValue
- ? t('Type your answer')
- : action.label ?? t('Other')
+ isChecked && !otherValue ? t('type') : action.label ?? t('other')
"
v-model="otherValue"
class="block w-full border-0 focus:ring-0"
@@ -54,7 +52,9 @@
e
- Enter
+ {{
+ t("enter")
+ }}
diff --git a/resources/js/forms/classic/interactions/FileAction.vue b/resources/js/forms/classic/interactions/FileAction.vue
index e4fe485f..f69a56a9 100644
--- a/resources/js/forms/classic/interactions/FileAction.vue
+++ b/resources/js/forms/classic/interactions/FileAction.vue
@@ -14,9 +14,11 @@
type="button"
class="underline text-primary px-5 py-1 rounded"
>
- Choose Files
+ {{ t("files_choose") }}
- or drop here
+ {{
+ t("files_drop")
+ }}
@@ -45,8 +47,10 @@ import { useConversation } from "@/stores/conversation";
import { useFileDialog, useDropZone } from "@vueuse/core";
import UploadFileItem from "@/forms/classic/components/UploadFileItem.vue";
import { computed, ref } from "vue";
+import { useI18n } from "vue-i18n";
const store = useConversation();
+const { t } = useI18n();
const props = defineProps<{
index: number;
@@ -98,6 +102,7 @@ const setFiles = (files: File[] | FileList | null) => {
) {
currentFiles.push(file);
} else {
+ // if validation fails, log an error and show it to the user
console.error("File type not allowed");
}
}
@@ -142,7 +147,10 @@ const allowedFileTypes = computed(() => {
const hasMaxFiles = computed(() => {
if (props.action?.options?.allowedFiles) {
- return currentFiles.value.length >= props.action.options.allowedFiles;
+ return (
+ currentFiles.value &&
+ currentFiles.value.length >= props.action.options.allowedFiles
+ );
}
return false;
diff --git a/resources/js/forms/classic/interactions/useButtonAction.ts b/resources/js/forms/classic/interactions/useButtonAction.ts
index d2e4018d..ef6e5263 100644
--- a/resources/js/forms/classic/interactions/useButtonAction.ts
+++ b/resources/js/forms/classic/interactions/useButtonAction.ts
@@ -1,10 +1,12 @@
import ButtonAction from "@/forms/classic/interactions/ButtonAction.vue";
+import { useI18n } from "vue-i18n";
export function useButtonAction(block: PublicFormBlockModel) {
+ const { t } = useI18n();
const useThis = ["radio", "checkbox"].includes(block.type);
const validator = (input: any) => {
- const validationMessage = "Please select an option.";
+ const validationMessage = t("validation.option_required");
if (block.is_required) {
if (!input) {
diff --git a/resources/js/forms/classic/interactions/useDateAction.ts b/resources/js/forms/classic/interactions/useDateAction.ts
index fe318993..9f2e1ff1 100644
--- a/resources/js/forms/classic/interactions/useDateAction.ts
+++ b/resources/js/forms/classic/interactions/useDateAction.ts
@@ -1,12 +1,14 @@
import DateAction from "@/forms/classic/interactions/DateAction.vue";
+import { useI18n } from "vue-i18n";
export function useDateAction(block: PublicFormBlockModel) {
+ const { t } = useI18n();
const useThis = ["date"].includes(block.type);
const validator = (input: any) => {
return {
valid: block.is_required ? input?.payload.length > 0 : true,
- message: "This field is required",
+ message: t("validation.field_required"),
};
};
diff --git a/resources/js/forms/classic/interactions/useFileAction.ts b/resources/js/forms/classic/interactions/useFileAction.ts
index 94d8163d..178519f4 100644
--- a/resources/js/forms/classic/interactions/useFileAction.ts
+++ b/resources/js/forms/classic/interactions/useFileAction.ts
@@ -1,13 +1,57 @@
import FileAction from "@/forms/classic/interactions/FileAction.vue";
+import { useI18n } from "vue-i18n";
export function useFileAction(block: PublicFormBlockModel) {
+ const { t } = useI18n();
const useThis = [
"input-file",
].includes(block.type);
const validator = (input: any) => {
- console.log("input file validation", input)
+ // check if the block is required
+ if (block.is_required && (!input?.payload || input?.payload.length === 0)) {
+ return {
+ valid: false,
+ message: t("validation.field_required"),
+ }
+ }
+
+ // get constraints from block file interaction
+ const interaction = block.interactions.find((interaction) => {
+ return interaction.type === "file";
+ })
+
+ if (!interaction) {
+ return {
+ valid: false,
+ message: t("No file interaction found"),
+ }
+ }
+
+ const maxFiles = interaction.options?.allowedFiles;
+ const maxFileSize = interaction.options?.allowedFileSize ? interaction.options?.allowedFileSize * Math.pow(10,6) : 0;
+
+ // check for max files constrains
+ if (maxFiles && input?.payload.length > maxFiles) {
+ return {
+ valid: false,
+ message: t(`Too many files uploaded`),
+ }
+ }
+
+ // check for file size constraints
+ if (input?.payload && input.payload.length > 0) {
+ for (const file of input.payload) {
+ // check for max file size
+ if (maxFileSize && file.size > maxFileSize) {
+ return {
+ valid: false,
+ message: t(`File size of ${file.name} too large`),
+ }
+ }
+ }
+ }
return {
valid: true,
diff --git a/resources/js/forms/classic/interactions/useInputAction.ts b/resources/js/forms/classic/interactions/useInputAction.ts
index 30251e11..fe44fceb 100644
--- a/resources/js/forms/classic/interactions/useInputAction.ts
+++ b/resources/js/forms/classic/interactions/useInputAction.ts
@@ -1,7 +1,9 @@
import InputAction from "@/forms/classic/interactions/InputAction.vue";
import { string, number } from "yup";
+import { useI18n } from "vue-i18n";
export function useInputAction(block: PublicFormBlockModel) {
+ const { t } = useI18n();
const useThis = [
"input-short",
"input-email",
@@ -28,35 +30,35 @@ export function useInputAction(block: PublicFormBlockModel) {
valid:
(!block.is_required && !input?.payload) ||
emailValidator.isValidSync(input?.payload),
- message: "Please enter a valid email.",
+ message: t("validation.valid_email"),
};
case "input-number":
return {
valid:
(!block.is_required && !input?.payload) ||
numberValidator.isValidSync(input?.payload),
- message: "Please enter a valid number.",
+ message: t("validation.valid_number"),
};
case "input-link":
return {
valid:
(!block.is_required && !input?.payload) ||
linkValidator.isValidSync(input?.payload),
- message: "Please enter a valid link.",
+ message: t("validation.valid_link"),
};
case "input-phone":
return {
valid:
(!block.is_required && !input?.payload) ||
phoneValidator.isValidSync(input?.payload),
- message: "Please enter a valid phone number.",
+ message: t("validation.valid_phone")
};
default:
return {
valid:
(!block.is_required && !input?.payload) ||
defaultValidator.isValidSync(input?.payload),
- message: "Please enter a valid short text.",
+ message: t("Please enter a valid short text."),
};
}
};
diff --git a/resources/js/forms/classic/interactions/useRangeAction.ts b/resources/js/forms/classic/interactions/useRangeAction.ts
index b47e1c98..4a0e390a 100644
--- a/resources/js/forms/classic/interactions/useRangeAction.ts
+++ b/resources/js/forms/classic/interactions/useRangeAction.ts
@@ -1,10 +1,11 @@
import RangeAction from "@/forms/classic/interactions/RangeAction.vue";
-
+import { useI18n } from "vue-i18n";
export function useRangeAction(block: PublicFormBlockModel) {
+ const { t } = useI18n();
const useThis = ["rating", "scale"].includes(block.type);
const validator = (input: any) => {
- const validationMessage = "Please choose a rating.";
+ const validationMessage = t("Please choose a rating.");
if (block.is_required) {
if (!input) {
diff --git a/resources/js/forms/classic/interactions/useTextareaAction.ts b/resources/js/forms/classic/interactions/useTextareaAction.ts
index b816bbe4..cede6432 100644
--- a/resources/js/forms/classic/interactions/useTextareaAction.ts
+++ b/resources/js/forms/classic/interactions/useTextareaAction.ts
@@ -1,6 +1,8 @@
import TextareaAction from "@/forms/classic/interactions/TextareaAction.vue";
+import { useI18n } from "vue-i18n";
export function useTextareaAction(block: PublicFormBlockModel) {
+ const { t } = useI18n();
const useThis = ["input-long"].includes(block.type);
const validator = (input: any) => {
@@ -8,7 +10,7 @@ export function useTextareaAction(block: PublicFormBlockModel) {
block.is_required &&
(!input || input?.payload?.trim().length === 0)
) {
- return { valid: false, message: "This field is required" };
+ return { valid: false, message: t("validation.field_required") };
}
const action = block.interactions[0];
@@ -22,7 +24,7 @@ export function useTextareaAction(block: PublicFormBlockModel) {
return {
valid: false,
message:
- "You have exceeded the maximum number of characters allowed.",
+ t("validation.max_characters"),
};
}
}
diff --git a/resources/locales/en.json b/resources/locales/en.json
index b1a77b2a..0baa3e0c 100644
--- a/resources/locales/en.json
+++ b/resources/locales/en.json
@@ -32,5 +32,7 @@
"form_submitted": "Form Submitted",
"find_us": "Find us here",
"enter": "Enter",
- "continue": "Continue"
+ "continue": "Continue",
+ "files_choose": "Choose files",
+ "files_drop": "or drop here"
}