diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index 4fa198ad..6244467c 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -17,7 +17,7 @@
"@vee-validate/i18n": "~4.9.6",
"@vee-validate/rules": "~4.9.6",
"bootstrap": "^5.3.3",
- "logitar-vue3-ui": "^2.0.5",
+ "logitar-vue3-ui": "^2.4.0",
"nanoid": "^5.0.7",
"pinia": "^2.1.7",
"pinia-plugin-persistedstate": "^3.2.1",
@@ -4542,9 +4542,9 @@
"dev": true
},
"node_modules/logitar-vue3-ui": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/logitar-vue3-ui/-/logitar-vue3-ui-2.0.5.tgz",
- "integrity": "sha512-7e6rE/6ledK9+BdrPHraOXneygLE9NEJnGXhFAuOJt/1UTdoxTN3iboU0GLX651y/9ULWFcdtKXTyyaNKc32Dw==",
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/logitar-vue3-ui/-/logitar-vue3-ui-2.4.0.tgz",
+ "integrity": "sha512-p4JHMHcF1UaDTm14FgHXUszx1/qiDdaHBmidKOGS23vfA7Z2MZqSpcJfjxc0Ggy9SSh+9/VfORtpesp1UqobsQ==",
"dependencies": {
"md5": "^2.3.0",
"nanoid": "^5.0.4"
diff --git a/frontend/package.json b/frontend/package.json
index 88dd8a34..d6a32294 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -24,7 +24,7 @@
"@vee-validate/i18n": "~4.9.6",
"@vee-validate/rules": "~4.9.6",
"bootstrap": "^5.3.3",
- "logitar-vue3-ui": "^2.0.5",
+ "logitar-vue3-ui": "^2.4.0",
"nanoid": "^5.0.7",
"pinia": "^2.1.7",
"pinia-plugin-persistedstate": "^3.2.1",
diff --git a/frontend/src/components/articles/ArticleSelect.vue b/frontend/src/components/articles/ArticleSelect.vue
index decf2326..f6c70ba4 100644
--- a/frontend/src/components/articles/ArticleSelect.vue
+++ b/frontend/src/components/articles/ArticleSelect.vue
@@ -1,25 +1,36 @@
-
+
diff --git a/frontend/src/components/articles/GtinInput.vue b/frontend/src/components/articles/GtinInput.vue
index 76178cdf..70efcc2c 100644
--- a/frontend/src/components/articles/GtinInput.vue
+++ b/frontend/src/components/articles/GtinInput.vue
@@ -1,16 +1,9 @@
-
+
diff --git a/frontend/src/components/banners/BannerSelect.vue b/frontend/src/components/banners/BannerSelect.vue
index 674860ff..92778408 100644
--- a/frontend/src/components/banners/BannerSelect.vue
+++ b/frontend/src/components/banners/BannerSelect.vue
@@ -1,25 +1,35 @@
-
+
diff --git a/frontend/src/components/departments/DepartmentEdit.vue b/frontend/src/components/departments/DepartmentEdit.vue
index 56c24f76..79d84f52 100644
--- a/frontend/src/components/departments/DepartmentEdit.vue
+++ b/frontend/src/components/departments/DepartmentEdit.vue
@@ -35,11 +35,22 @@ function hide(): void {
modalRef.value?.hide();
}
+function setModel(department?: Department) {
+ number.value = department?.number ?? "";
+ displayName.value = department?.displayName ?? "";
+ description.value = department?.description ?? "";
+}
+
const emit = defineEmits<{
(e: "error", value: unknown): void;
(e: "saved", value: Department): void;
}>();
+function onCancel(): void {
+ setModel(props.department);
+ hide();
+}
+
const { handleSubmit, isSubmitting } = useForm();
const onSubmit = handleSubmit(async () => {
try {
@@ -61,9 +72,7 @@ const onSubmit = handleSubmit(async () => {
watchEffect(() => {
const department = props.department;
- number.value = department?.number ?? "";
- displayName.value = department?.displayName ?? "";
- description.value = department?.description ?? "";
+ setModel(department);
});
@@ -83,7 +92,7 @@ watchEffect(() => {
-
+
refresh(payload), { deep: true, immediate: true });
-
+
diff --git a/frontend/src/components/departments/DepartmentSelect.vue b/frontend/src/components/departments/DepartmentSelect.vue
index 1a1947e8..3bb21b5a 100644
--- a/frontend/src/components/departments/DepartmentSelect.vue
+++ b/frontend/src/components/departments/DepartmentSelect.vue
@@ -1,28 +1,17 @@
-
+
diff --git a/frontend/src/components/products/SkuInput.vue b/frontend/src/components/products/SkuInput.vue
index 86f2d225..045a4503 100644
--- a/frontend/src/components/products/SkuInput.vue
+++ b/frontend/src/components/products/SkuInput.vue
@@ -1,16 +1,9 @@
-
+
diff --git a/frontend/src/components/products/UnitTypeSelect.vue b/frontend/src/components/products/UnitTypeSelect.vue
index 615ea329..9d3c891d 100644
--- a/frontend/src/components/products/UnitTypeSelect.vue
+++ b/frontend/src/components/products/UnitTypeSelect.vue
@@ -1,17 +1,18 @@
-
+
diff --git a/frontend/src/components/receipts/EmptySelect.vue b/frontend/src/components/receipts/EmptySelect.vue
index 430f4ee6..049d1b1d 100644
--- a/frontend/src/components/receipts/EmptySelect.vue
+++ b/frontend/src/components/receipts/EmptySelect.vue
@@ -1,18 +1,18 @@
-
+
diff --git a/frontend/src/components/receipts/IssuedOnInput.vue b/frontend/src/components/receipts/IssuedOnInput.vue
index a3594568..f17f2f0c 100644
--- a/frontend/src/components/receipts/IssuedOnInput.vue
+++ b/frontend/src/components/receipts/IssuedOnInput.vue
@@ -1,25 +1,24 @@
-
+
diff --git a/frontend/src/components/receipts/ReceiptLinesTextarea.vue b/frontend/src/components/receipts/ReceiptLinesTextarea.vue
index 968d2ae7..989ddde7 100644
--- a/frontend/src/components/receipts/ReceiptLinesTextarea.vue
+++ b/frontend/src/components/receipts/ReceiptLinesTextarea.vue
@@ -1,16 +1,9 @@
-
+
diff --git a/frontend/src/components/receipts/StatusSelect.vue b/frontend/src/components/receipts/StatusSelect.vue
index f453d9cb..118cf4a2 100644
--- a/frontend/src/components/receipts/StatusSelect.vue
+++ b/frontend/src/components/receipts/StatusSelect.vue
@@ -1,18 +1,18 @@
-
+
diff --git a/frontend/src/components/shared/AppInput.vue b/frontend/src/components/shared/AppInput.vue
new file mode 100644
index 00000000..d0738535
--- /dev/null
+++ b/frontend/src/components/shared/AppInput.vue
@@ -0,0 +1,124 @@
+
+
+
+
+
+ {{ errorMessage }}
+
+
+
+
diff --git a/frontend/src/components/shared/AppSelect.vue b/frontend/src/components/shared/AppSelect.vue
new file mode 100644
index 00000000..6f242985
--- /dev/null
+++ b/frontend/src/components/shared/AppSelect.vue
@@ -0,0 +1,87 @@
+
+
+
+
+
+ {{ errorMessage }}
+
+
+
+
diff --git a/frontend/src/components/shared/AppTextarea.vue b/frontend/src/components/shared/AppTextarea.vue
new file mode 100644
index 00000000..ee7b6ef4
--- /dev/null
+++ b/frontend/src/components/shared/AppTextarea.vue
@@ -0,0 +1,96 @@
+
+
+
+
+
+ {{ errorMessage }}
+
+
+
+
diff --git a/frontend/src/components/shared/CountSelect.vue b/frontend/src/components/shared/CountSelect.vue
index 0d48a39f..cc755176 100644
--- a/frontend/src/components/shared/CountSelect.vue
+++ b/frontend/src/components/shared/CountSelect.vue
@@ -1,16 +1,16 @@
-
+
diff --git a/frontend/src/components/shared/DateTimeInput.vue b/frontend/src/components/shared/DateTimeInput.vue
new file mode 100644
index 00000000..e2e9d24c
--- /dev/null
+++ b/frontend/src/components/shared/DateTimeInput.vue
@@ -0,0 +1,59 @@
+
+
+
+
+
diff --git a/frontend/src/components/shared/DescriptionTextarea.vue b/frontend/src/components/shared/DescriptionTextarea.vue
index 0bbbdb64..390adb23 100644
--- a/frontend/src/components/shared/DescriptionTextarea.vue
+++ b/frontend/src/components/shared/DescriptionTextarea.vue
@@ -1,16 +1,9 @@
-
+
diff --git a/frontend/src/components/shared/DisplayNameInput.vue b/frontend/src/components/shared/DisplayNameInput.vue
index e1f6a352..58e62c14 100644
--- a/frontend/src/components/shared/DisplayNameInput.vue
+++ b/frontend/src/components/shared/DisplayNameInput.vue
@@ -1,16 +1,10 @@
-
+
diff --git a/frontend/src/components/shared/FlagInput.vue b/frontend/src/components/shared/FlagInput.vue
index 8db305bc..e7ff78a2 100644
--- a/frontend/src/components/shared/FlagInput.vue
+++ b/frontend/src/components/shared/FlagInput.vue
@@ -1,16 +1,12 @@
-
+
diff --git a/frontend/src/components/shared/FlagsInput.vue b/frontend/src/components/shared/FlagsInput.vue
index f9f24d41..2ab25674 100644
--- a/frontend/src/components/shared/FlagsInput.vue
+++ b/frontend/src/components/shared/FlagsInput.vue
@@ -1,16 +1,9 @@
-
+
diff --git a/frontend/src/components/shared/NumberInput.vue b/frontend/src/components/shared/NumberInput.vue
index 6ed2c3ed..7e773e90 100644
--- a/frontend/src/components/shared/NumberInput.vue
+++ b/frontend/src/components/shared/NumberInput.vue
@@ -1,16 +1,10 @@
-
+
diff --git a/frontend/src/components/shared/PriceInput.vue b/frontend/src/components/shared/PriceInput.vue
index 1532ba9e..b787e11c 100644
--- a/frontend/src/components/shared/PriceInput.vue
+++ b/frontend/src/components/shared/PriceInput.vue
@@ -1,19 +1,23 @@
-
+
-
+
diff --git a/frontend/src/components/shared/SearchInput.vue b/frontend/src/components/shared/SearchInput.vue
index 20f749d0..a8a17450 100644
--- a/frontend/src/components/shared/SearchInput.vue
+++ b/frontend/src/components/shared/SearchInput.vue
@@ -1,16 +1,12 @@
-
+
diff --git a/frontend/src/components/shared/SortSelect.vue b/frontend/src/components/shared/SortSelect.vue
index a77bdad1..2b3e58e1 100644
--- a/frontend/src/components/shared/SortSelect.vue
+++ b/frontend/src/components/shared/SortSelect.vue
@@ -1,21 +1,18 @@
-
+
diff --git a/frontend/src/components/stores/StoreSelect.vue b/frontend/src/components/stores/StoreSelect.vue
index 5dde7faa..db867a70 100644
--- a/frontend/src/components/stores/StoreSelect.vue
+++ b/frontend/src/components/stores/StoreSelect.vue
@@ -1,26 +1,38 @@
-
+
diff --git a/frontend/src/components/taxes/TaxCodeInput.vue b/frontend/src/components/taxes/TaxCodeInput.vue
index 571b36cb..b3c3948b 100644
--- a/frontend/src/components/taxes/TaxCodeInput.vue
+++ b/frontend/src/components/taxes/TaxCodeInput.vue
@@ -1,16 +1,10 @@
-
+
diff --git a/frontend/src/components/taxes/TaxRateInput.vue b/frontend/src/components/taxes/TaxRateInput.vue
index a3c74d13..61c68ffe 100644
--- a/frontend/src/components/taxes/TaxRateInput.vue
+++ b/frontend/src/components/taxes/TaxRateInput.vue
@@ -1,19 +1,14 @@
-
+
diff --git a/frontend/src/components/users/AddressCountrySelect.vue b/frontend/src/components/users/AddressCountrySelect.vue
index a0625500..ff62b5f8 100644
--- a/frontend/src/components/users/AddressCountrySelect.vue
+++ b/frontend/src/components/users/AddressCountrySelect.vue
@@ -1,20 +1,19 @@
-
+
diff --git a/frontend/src/components/users/AddressLocalityInput.vue b/frontend/src/components/users/AddressLocalityInput.vue
index d61e797d..52636efa 100644
--- a/frontend/src/components/users/AddressLocalityInput.vue
+++ b/frontend/src/components/users/AddressLocalityInput.vue
@@ -1,16 +1,10 @@
-
+
diff --git a/frontend/src/components/users/AddressPostalCodeInput.vue b/frontend/src/components/users/AddressPostalCodeInput.vue
index b748611a..2dc742f3 100644
--- a/frontend/src/components/users/AddressPostalCodeInput.vue
+++ b/frontend/src/components/users/AddressPostalCodeInput.vue
@@ -1,25 +1,12 @@
-
diff --git a/frontend/src/components/users/AddressRegionSelect.vue b/frontend/src/components/users/AddressRegionSelect.vue
index 3e32899b..de0b21c5 100644
--- a/frontend/src/components/users/AddressRegionSelect.vue
+++ b/frontend/src/components/users/AddressRegionSelect.vue
@@ -1,26 +1,19 @@
-
+
diff --git a/frontend/src/components/users/AddressStreetTextarea.vue b/frontend/src/components/users/AddressStreetTextarea.vue
index e50c015b..2cbb4311 100644
--- a/frontend/src/components/users/AddressStreetTextarea.vue
+++ b/frontend/src/components/users/AddressStreetTextarea.vue
@@ -1,17 +1,10 @@
-
+
diff --git a/frontend/src/components/users/EmailAddressInput.vue b/frontend/src/components/users/EmailAddressInput.vue
index 61d62827..a015313d 100644
--- a/frontend/src/components/users/EmailAddressInput.vue
+++ b/frontend/src/components/users/EmailAddressInput.vue
@@ -1,17 +1,9 @@
-
+
diff --git a/frontend/src/components/users/PhoneExtensionInput.vue b/frontend/src/components/users/PhoneExtensionInput.vue
index 103e6529..c4cce17e 100644
--- a/frontend/src/components/users/PhoneExtensionInput.vue
+++ b/frontend/src/components/users/PhoneExtensionInput.vue
@@ -1,16 +1,9 @@
-
+
diff --git a/frontend/src/components/users/PhoneNumberInput.vue b/frontend/src/components/users/PhoneNumberInput.vue
index 9fe46d03..48ad7afd 100644
--- a/frontend/src/components/users/PhoneNumberInput.vue
+++ b/frontend/src/components/users/PhoneNumberInput.vue
@@ -1,17 +1,10 @@
-
+
diff --git a/frontend/src/resources/countries.json b/frontend/src/resources/countries.json
index a40a3fb0..cf815cd7 100644
--- a/frontend/src/resources/countries.json
+++ b/frontend/src/resources/countries.json
@@ -1,7 +1,7 @@
[
{
"code": "CA",
- "postalCode": "[ABCEGHJ-NPRSTVXY]\\d[ABCEGHJ-NPRSTV-Z][ \\-]?\\d[ABCEGHJ-NPRSTV-Z]\\d",
+ "postalCode": "^[ABCEGHJ-NPRSTVXY]\\d[ABCEGHJ-NPRSTV-Z][ \\-]?\\d[ABCEGHJ-NPRSTV-Z]\\d$",
"regions": ["AB", "BC", "MB", "NB", "NL", "NT", "NS", "NU", "ON", "PE", "QC", "SK", "YT"]
}
]
diff --git a/frontend/src/types/validation.ts b/frontend/src/types/validation.ts
new file mode 100644
index 00000000..8efd61c5
--- /dev/null
+++ b/frontend/src/types/validation.ts
@@ -0,0 +1,23 @@
+export type ValidationListeners = {
+ blur: (e: unknown, shouldValidate?: boolean) => void;
+ change: (e: unknown, shouldValidate?: boolean) => void;
+ input: (e: unknown, shouldValidate?: boolean) => void;
+};
+
+export type ValidationRules = {
+ allowed_characters?: string;
+ confirmed?: string[];
+ email?: boolean;
+ max_length?: number;
+ max_value?: number;
+ min_length?: number;
+ min_value?: number;
+ regex?: string;
+ require_digit?: boolean;
+ require_lowercase?: boolean;
+ require_non_alphanumeric?: boolean;
+ require_uppercase?: boolean;
+ required?: boolean;
+ unique_chars?: number;
+ url?: boolean;
+};
diff --git a/frontend/src/validation/index.ts b/frontend/src/validation/index.ts
index 544f86ef..c57474dc 100644
--- a/frontend/src/validation/index.ts
+++ b/frontend/src/validation/index.ts
@@ -2,6 +2,7 @@ import { configure, defineRule } from "vee-validate";
import { email, max, max_value, min, min_value, regex, required } from "@vee-validate/rules";
import { localize } from "@vee-validate/i18n";
+import allowedCharacters from "./rules/allowedCharacters";
import confirmed from "./rules/confirmed";
import identifier from "./rules/identifier";
import requireDigit from "./rules/requireDigit";
@@ -11,8 +12,8 @@ import requireUppercase from "./rules/requireUppercase";
import slug from "./rules/slug";
import uniqueChars from "./rules/uniqueChars";
import url from "./rules/url";
-import username from "./rules/username";
+defineRule("allowed_characters", allowedCharacters);
defineRule("confirmed", confirmed);
defineRule("email", email);
defineRule("identifier", identifier);
@@ -29,7 +30,6 @@ defineRule("required", required);
defineRule("slug", slug);
defineRule("unique_chars", uniqueChars);
defineRule("url", url);
-defineRule("username", username);
import en from "./locales/errors.en.json";
import fr from "./locales/errors.fr.json";
diff --git a/frontend/src/validation/locales/errors.en.json b/frontend/src/validation/locales/errors.en.json
index 85cdc743..e6c3f349 100644
--- a/frontend/src/validation/locales/errors.en.json
+++ b/frontend/src/validation/locales/errors.en.json
@@ -1,4 +1,5 @@
{
+ "allowed_characters": "The {field} may only contain the following characters: 0:{allowedCharacters}",
"confirmed": "The 1:{target} and the {field} do not match.",
"email": "Please enter a valid email address.",
"identifier": "The {field} cannot start with a digit and it may only contain letters, digits and underscores (_).",
@@ -14,6 +15,5 @@
"required": "The {field} is required.",
"slug": "The {field} must be composed of non-empty alphanumeric words separated by hyphens (-).",
"unique_chars": "The {field} must contain at least 0:{count} different characters.",
- "url": "Please enter a valid URL. Valid URLs start with http:// or https://.",
- "username": "The {field} may only contain the following characters: 0:{allowedCharacters}"
+ "url": "Please enter a valid URL. Valid URLs start with http:// or https://."
}
diff --git a/frontend/src/validation/locales/errors.fr.json b/frontend/src/validation/locales/errors.fr.json
index 20810960..f10e1fe3 100644
--- a/frontend/src/validation/locales/errors.fr.json
+++ b/frontend/src/validation/locales/errors.fr.json
@@ -1,4 +1,5 @@
{
+ "allowed_characters": "Le champs « {field} » ne peut contenir que les caractères suivants : 0:{allowedCharacters}",
"confirmed": "Les champs « 1:{target} » et « {field} » ne correspondent pas.",
"email": "Veuillez entrer une adresse courriel valide.",
"identifier": "Le champs « {field} » ne peut commencer par un chiffre et il ne peut contenir que des lettres, des chiffres et des tirets bas (_).",
@@ -14,6 +15,5 @@
"required": "Le champs « {field} » est requis.",
"slug": "Le champs « {field} » doit être composé de mots alphanumériques non vides séparés par un tiret (-).",
"unique_chars": "Le champs « {field} » doit contenir au moins 0:{count} caractères uniques.",
- "url": "Veuillez entre un lien valide. Un lien valide débute par http:// ou https://.",
- "username": "Le champs « {field} » ne peut contenir que les caractères suivants : 0:{allowedCharacters}"
+ "url": "Veuillez entre un lien valide. Un lien valide débute par http:// ou https://."
}
diff --git a/frontend/src/validation/rules/__tests__/allowedCharacters.spec.ts b/frontend/src/validation/rules/__tests__/allowedCharacters.spec.ts
new file mode 100644
index 00000000..09bf6e5c
--- /dev/null
+++ b/frontend/src/validation/rules/__tests__/allowedCharacters.spec.ts
@@ -0,0 +1,22 @@
+import { describe, it, expect } from "vitest";
+
+import allowedCharacters from "../allowedCharacters";
+
+const allowedCharacterList: string = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@+";
+
+describe("allowedCharacters", () => {
+ it.concurrent("should return false when the value contains characters that are not allowed", () => {
+ expect(allowedCharacters(undefined, [undefined as any])).toBe(false);
+ expect(allowedCharacters(undefined, [""])).toBe(false);
+ expect(allowedCharacters(undefined, [allowedCharacterList])).toBe(false);
+ expect(allowedCharacters("test!", [allowedCharacterList])).toBe(false);
+ expect(allowedCharacters(" test", [allowedCharacterList])).toBe(false);
+ });
+
+ it.concurrent("should return true when the value only contains allowed characters", () => {
+ expect(allowedCharacters("carluiz", [undefined as any])).toBe(true);
+ expect(allowedCharacters("carluiz", [""])).toBe(true);
+ expect(allowedCharacters("carluiz", [allowedCharacterList])).toBe(true);
+ expect(allowedCharacters("carlos.luiz@test.com", [allowedCharacterList])).toBe(true);
+ });
+});
diff --git a/frontend/src/validation/rules/__tests__/username.spec.ts b/frontend/src/validation/rules/__tests__/username.spec.ts
deleted file mode 100644
index 14148cf4..00000000
--- a/frontend/src/validation/rules/__tests__/username.spec.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-import { describe, it, expect } from "vitest";
-
-import username from "../username";
-
-const allowedCharacters: string = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@+";
-
-describe("username", () => {
- it.concurrent("should return false when the value contains characters that are not allowed", () => {
- expect(username(undefined, [undefined as any])).toBe(false);
- expect(username(undefined, [""])).toBe(false);
- expect(username(undefined, [allowedCharacters])).toBe(false);
- expect(username("test!", [allowedCharacters])).toBe(false);
- expect(username(" test", [allowedCharacters])).toBe(false);
- });
-
- it.concurrent("should return true when the value only contains allowed characters", () => {
- expect(username("carluiz", [undefined as any])).toBe(true);
- expect(username("carluiz", [""])).toBe(true);
- expect(username("carluiz", [allowedCharacters])).toBe(true);
- expect(username("carlos.luiz@test.com", [allowedCharacters])).toBe(true);
- });
-});
diff --git a/frontend/src/validation/rules/username.ts b/frontend/src/validation/rules/allowedCharacters.ts
similarity index 100%
rename from frontend/src/validation/rules/username.ts
rename to frontend/src/validation/rules/allowedCharacters.ts
diff --git a/frontend/src/views/account/ProfileView.vue b/frontend/src/views/account/ProfileView.vue
index 428be37c..97f07d4f 100644
--- a/frontend/src/views/account/ProfileView.vue
+++ b/frontend/src/views/account/ProfileView.vue
@@ -1,5 +1,35 @@
+
+
Profile
+
diff --git a/frontend/src/views/account/SignInView.vue b/frontend/src/views/account/SignInView.vue
index 2d95e19d..8a7aa83d 100644
--- a/frontend/src/views/account/SignInView.vue
+++ b/frontend/src/views/account/SignInView.vue
@@ -1,10 +1,11 @@