diff --git a/frontend/src/components/Contributions/ContributionForm.spec.js b/frontend/src/components/Contributions/ContributionForm.spec.js index 42ef6d02a..7ef941dc8 100644 --- a/frontend/src/components/Contributions/ContributionForm.spec.js +++ b/frontend/src/components/Contributions/ContributionForm.spec.js @@ -5,6 +5,7 @@ import ContributionForm from './ContributionForm.vue' vi.mock('vue-i18n', () => ({ useI18n: () => ({ t: (key) => key, + d: (date) => date, }), })) diff --git a/frontend/src/components/Contributions/ContributionForm.vue b/frontend/src/components/Contributions/ContributionForm.vue index 0fc0fa05d..f4ea3b7cc 100644 --- a/frontend/src/components/Contributions/ContributionForm.vue +++ b/frontend/src/components/Contributions/ContributionForm.vue @@ -43,7 +43,7 @@ :label="$t('form.hours')" placeholder="0.01" step="0.01" - type="number" + type="text" :rules="validationSchema.fields.hours" :disable-smart-valid-state="disableSmartValidState" @update:model-value="updateField" @@ -92,9 +92,8 @@ import { reactive, computed, ref, onMounted, onUnmounted, toRaw } from 'vue' import { useI18n } from 'vue-i18n' import ValidatedInput from '@/components/Inputs/ValidatedInput' import LabeledInput from '@/components/Inputs/LabeledInput' -import { memo as memoSchema } from '@/validationSchemas' import OpenCreationsAmount from './OpenCreationsAmount.vue' -import { object, date as dateSchema, number } from 'yup' +import { object, date as dateSchema, number, string } from 'yup' import { GDD_PER_HOUR } from '../../constants' const amountToHours = (amount) => parseFloat(amount / GDD_PER_HOUR).toFixed(2) @@ -108,7 +107,7 @@ const props = defineProps({ const emit = defineEmits(['upsert-contribution', 'abort']) -const { t } = useI18n() +const { t, d } = useI18n() const entityDataToForm = computed(() => ({ ...props.modelValue, @@ -151,16 +150,26 @@ const validationSchema = computed(() => { // The date field is required and needs to be a valid date // contribution date contributionDate: dateSchema() - .required() - .min(minimalDate.value.toISOString().slice(0, 10)) // min date is first day of last month - .max(now.value.toISOString().slice(0, 10)), // date cannot be in the future - memo: memoSchema, + .required('form.validation.contributionDate.required') + .min(minimalDate.value.toISOString().slice(0, 10), ({ min }) => ({ + key: 'form.validation.contributionDate.min', + values: { min: d(min) }, + })) // min date is first day of last month + .max(now.value.toISOString().slice(0, 10), ({ max }) => ({ + key: 'form.validation.contributionDate.max', + values: { max: d(max) }, + })), // date cannot be in the future + memo: string() + .min(5, ({ min }) => ({ key: 'form.validation.contributionMemo.min', values: { min } })) + .max(255, ({ max }) => ({ key: 'form.validation.contributionMemo.max', values: { max } })) + .required('form.validation.contributionMemo.required'), hours: number() + .typeError({ key: 'form.validation.hours.typeError', values: { min: 0.01, max: maxHours } }) .required() - .transform((value, originalValue) => (originalValue === '' ? undefined : value)) - .min(0.01, ({ min }) => ({ key: 'form.validation.gddCreationTime.min', values: { min } })) - .max(maxHours, ({ max }) => ({ key: 'form.validation.gddCreationTime.max', values: { max } })) - .test('decimal-places', 'form.validation.gddCreationTime.decimal-places', (value) => { + // .transform((value, originalValue) => (originalValue === '' ? undefined : value)) + .min(0.01, ({ min }) => ({ key: 'form.validation.hours.min', values: { min } })) + .max(maxHours, ({ max }) => ({ key: 'form.validation.hours.max', values: { max } })) + .test('decimal-places', 'form.validation.hours.decimal-places', (value) => { if (value === undefined || value === null) return true return /^\d+(\.\d{0,2})?$/.test(value.toString()) }), diff --git a/frontend/src/components/GddSend/TransactionForm.vue b/frontend/src/components/GddSend/TransactionForm.vue index c612b24be..510ba3786 100644 --- a/frontend/src/components/GddSend/TransactionForm.vue +++ b/frontend/src/components/GddSend/TransactionForm.vue @@ -184,9 +184,15 @@ const userName = ref('') const validationSchema = computed(() => { return object({ memo: memoSchema, - identifier: !userIdentifier.value ? identifierSchema.required() : identifierSchema, + identifier: !userIdentifier.value + ? identifierSchema.required('form.validation.identifier.required') + : identifierSchema, amount: number() .required() + .typeError({ + key: 'form.validation.amount.typeError', + values: { min: 0.01, max: props.balance }, + }) .transform((value, originalValue) => { if (typeof originalValue === 'string') { return Number(originalValue.replace(',', '.')) diff --git a/frontend/src/components/Inputs/ValidatedInput.vue b/frontend/src/components/Inputs/ValidatedInput.vue index 67362131d..6eaba5681 100644 --- a/frontend/src/components/Inputs/ValidatedInput.vue +++ b/frontend/src/components/Inputs/ValidatedInput.vue @@ -71,9 +71,6 @@ const smartValidState = computed(() => { return valid.value ? true : null }) const errorMessage = computed(() => { - if (model.value === undefined || model.value === '' || model.value === null) { - return undefined - } try { props.rules.validateSync(model.value) return undefined diff --git a/frontend/src/locales/de.json b/frontend/src/locales/de.json index a94099015..7a68d3819 100644 --- a/frontend/src/locales/de.json +++ b/frontend/src/locales/de.json @@ -204,26 +204,39 @@ "username-placeholder": "Wähle deinen Benutzernamen", "validation": { "amount": { - "min": "Der Betrag sollte mindestens {min} groß sein", - "max": "Der Betrag sollte höchstens {max} groß sein", - "decimal-places": "Der Betrag sollte maximal zwei Nachkommastellen enthalten" + "min": "Der Betrag sollte mindestens {min} groß sein.", + "max": "Der Betrag sollte höchstens {max} groß sein.", + "decimal-places": "Der Betrag sollte maximal zwei Nachkommastellen enthalten.", + "typeError": "Der Betrag sollte eine Zahl zwischen {min} und {max} mit höchstens zwei Nachkommastellen sein." }, - "gddCreationTime": { - "min": "Die Stunden sollten mindestens {min} groß sein", - "max": "Die Stunden sollten höchstens {max} groß sein", - "decimal-places": "Die Stunden sollten maximal zwei Nachkommastellen enthalten" + "contributionDate": { + "required": "Das Beitragsdatum ist ein Pflichtfeld.", + "min": "Das Frühste Beitragsdatum ist {min}.", + "max": "Das Späteste Beitragsdatum ist heute, der {max}." }, - "gddSendAmount": "Das Feld {_field_} muss eine Zahl zwischen {min} und {max} mit höchstens zwei Nachkommastellen sein", - "is-not": "Du kannst dir selbst keine Gradidos überweisen", + "contributionMemo": { + "min": "Die Tätigkeitsbeschreibung sollte mindestens {min} Zeichen lang sein.", + "max": "Die Tätigkeitsbeschreibung sollte höchstens {max} Zeichen lang sein.", + "required": "Die Tätigkeitsbeschreibung ist ein Pflichtfeld." + }, + "hours": { + "min": "Die Stunden sollten mindestens {min} groß sein.", + "max": "Die Stunden sollten höchstens {max} groß sein.", + "decimal-places": "Die Stunden sollten maximal zwei Nachkommastellen enthalten.", + "typeError": "Die Stunden sollten eine Zahl zwischen {min} und {max} mit höchstens zwei Nachkommastellen sein." + }, + "gddSendAmount": "Das Feld {_field_} muss eine Zahl zwischen {min} und {max} mit höchstens zwei Nachkommastellen sein.", + "is-not": "Du kannst dir selbst keine Gradidos überweisen!", "memo": { - "min": "Die Tätigkeitsbeschreibung sollte mindestens {min} Zeichen lang sein", - "max": "Die Tätigkeitsbeschreibung sollte höchstens {max} Zeichen lang sein" + "min": "Die Nachricht sollte mindestens {min} Zeichen lang sein.", + "max": "Die Nachricht sollte höchstens {max} Zeichen lang sein.", + "required": "Die Nachricht ist ein Pflichtfeld." }, "requiredField": "{fieldName} ist ein Pflichtfeld", "username-allowed-chars": "Der Nutzername darf nur aus Buchstaben (ohne Umlaute), Zahlen, Binde- oder Unterstrichen bestehen.", "username-hyphens": "Binde- oder Unterstriche müssen zwischen Buchstaben oder Zahlen stehen.", "username-unique": "Der Nutzername ist bereits vergeben.", - "valid-identifier": "Muss eine Email, ein Nutzernamen oder eine gradido ID sein." + "valid-identifier": "Muss eine Email, ein Nutzernamen oder eine Gradido ID sein." }, "your_amount": "Dein Betrag" }, diff --git a/frontend/src/locales/en.json b/frontend/src/locales/en.json index ec26e866d..69825bd7e 100644 --- a/frontend/src/locales/en.json +++ b/frontend/src/locales/en.json @@ -204,20 +204,33 @@ "username-placeholder": "Choose your username", "validation": { "amount": { - "min": "The amount should be at least {min} in size", - "max": "The amount should not be larger than {max}", - "decimal-places": "The amount should contain a maximum of two decimal places" + "min": "The amount should be at least {min} in size.", + "max": "The amount should not be larger than {max}.", + "decimal-places": "The amount should contain a maximum of two decimal places.", + "typeError": "The amount should be a number between {min} and {max} with at most two digits after the decimal point." }, - "gddCreationTime": { - "min": "The hours should be at least {min} in size", - "max": "The hours should not be larger than {max}", - "decimal-places": "The hours should contain a maximum of two decimal places" + "contributionDate": { + "required": "The contribution date is a required field.", + "min": "The earliest contribution date is {min}.", + "max": "The latest contribution date is today, {max}." }, - "gddSendAmount": "The {_field_} field must be a number between {min} and {max} with at most two digits after the decimal point", - "is-not": "You cannot send Gradidos to yourself", + "contributionMemo": { + "min": "The job description should be at least {min} characters long.", + "max": "The job description should not be longer than {max} characters.", + "required": "The job description is required." + }, + "hours": { + "min": "The hours should be at least {min} in size.", + "max": "The hours should not be larger than {max}.", + "decimal-places": "The hours should contain a maximum of two decimal places.", + "typeError": "The hours should be a number between {min} and {max} with at most two digits after the decimal point." + }, + "gddSendAmount": "The {_field_} field must be a number between {min} and {max} with at most two digits after the decimal point.", + "is-not": "You cannot send Gradidos to yourself!", "memo": { - "min": "The job description should be at least {min} characters long", - "max": "The job description should not be longer than {max} characters" + "min": "The message should be at least {min} characters long.", + "max": "The message should not be longer than {max} characters.", + "required": "The message is required." }, "requiredField": "The {fieldName} field is required", "username-allowed-chars": "The username may only contain letters, numbers, hyphens or underscores.", diff --git a/frontend/src/validationSchemas.js b/frontend/src/validationSchemas.js index 9c21aec66..eff976c84 100644 --- a/frontend/src/validationSchemas.js +++ b/frontend/src/validationSchemas.js @@ -22,7 +22,7 @@ export const translateYupErrorString = (error, t) => { } export const memo = string() - .required('contribution.yourActivity') + .required('form.validation.memo.required') .min(5, ({ min }) => ({ key: 'form.validation.memo.min', values: { min } })) .max(255, ({ max }) => ({ key: 'form.validation.memo.max', values: { max } }))