From 3b218a8da3ccb32e0e5846068aa6727fe3cade20 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Thu, 24 Jul 2025 15:59:09 +0200 Subject: [PATCH] refactor TransactionForm, remove not longer needed components --- frontend/src/components/CommunitySwitch.vue | 5 +- .../Contributions/ContributionForm.spec.js | 15 --- .../GddSend/TransactionForm.spec.js | 79 +++++------ .../components/GddSend/TransactionForm.vue | 101 +++++++++----- .../src/components/Inputs/InputAmount.spec.js | 125 ------------------ .../src/components/Inputs/InputAmount.vue | 88 ------------ .../src/components/Inputs/InputIdentifier.vue | 61 --------- .../components/Inputs/InputTextarea.spec.js | 125 ------------------ .../src/components/Inputs/InputTextarea.vue | 64 --------- frontend/src/locales/de.json | 5 + frontend/src/locales/en.json | 5 + frontend/src/validationSchemas.js | 18 +++ 12 files changed, 130 insertions(+), 561 deletions(-) delete mode 100644 frontend/src/components/Inputs/InputAmount.spec.js delete mode 100644 frontend/src/components/Inputs/InputAmount.vue delete mode 100644 frontend/src/components/Inputs/InputIdentifier.vue delete mode 100644 frontend/src/components/Inputs/InputTextarea.spec.js delete mode 100644 frontend/src/components/Inputs/InputTextarea.vue diff --git a/frontend/src/components/CommunitySwitch.vue b/frontend/src/components/CommunitySwitch.vue index 8775e8667..b081f5d93 100644 --- a/frontend/src/components/CommunitySwitch.vue +++ b/frontend/src/components/CommunitySwitch.vue @@ -22,7 +22,7 @@ diff --git a/frontend/src/components/Inputs/InputIdentifier.vue b/frontend/src/components/Inputs/InputIdentifier.vue deleted file mode 100644 index 3381e152f..000000000 --- a/frontend/src/components/Inputs/InputIdentifier.vue +++ /dev/null @@ -1,61 +0,0 @@ - - diff --git a/frontend/src/components/Inputs/InputTextarea.spec.js b/frontend/src/components/Inputs/InputTextarea.spec.js deleted file mode 100644 index dc04b5b63..000000000 --- a/frontend/src/components/Inputs/InputTextarea.spec.js +++ /dev/null @@ -1,125 +0,0 @@ -import { mount } from '@vue/test-utils' -import { describe, it, expect, beforeEach, vi } from 'vitest' -import InputTextarea from './InputTextarea' -import { useField } from 'vee-validate' -import { BFormGroup, BFormInvalidFeedback, BFormTextarea } from 'bootstrap-vue-next' - -vi.mock('vee-validate', () => ({ - useField: vi.fn(), -})) - -vi.mock('vue-i18n', () => ({ - useI18n: () => ({ - t: (key) => key, - }), -})) - -describe('InputTextarea', () => { - let wrapper - - const createWrapper = (props = {}) => { - return mount(InputTextarea, { - props: { - rules: {}, - name: 'input-field-name', - label: 'input-field-label', - placeholder: 'input-field-placeholder', - ...props, - }, - global: { - components: { - BFormGroup, - BFormTextarea, - BFormInvalidFeedback, - }, - }, - }) - } - - beforeEach(() => { - vi.mocked(useField).mockReturnValue({ - value: '', - errorMessage: '', - meta: { valid: true }, - }) - wrapper = createWrapper() - }) - - it('renders the component InputTextarea', () => { - expect(wrapper.find('[data-test="input-textarea"]').exists()).toBe(true) - }) - - it('has a textarea field', () => { - expect(wrapper.findComponent({ name: 'BFormTextarea' }).exists()).toBe(true) - }) - - describe('properties', () => { - it('has the correct id', () => { - const textarea = wrapper.findComponent({ name: 'BFormTextarea' }) - expect(textarea.attributes('id')).toBe('input-field-name-input-field') - }) - - it('has the correct placeholder', () => { - const textarea = wrapper.findComponent({ name: 'BFormTextarea' }) - expect(textarea.attributes('placeholder')).toBe('input-field-placeholder') - }) - - it('has the correct label', () => { - const label = wrapper.find('label') - expect(label.text()).toBe('input-field-label') - }) - - it('has the correct label-for attribute', () => { - const label = wrapper.find('label') - expect(label.attributes('for')).toBe('input-field-name-input-field') - }) - }) - - describe('input value changes', () => { - it('updates the model value when input changes', async () => { - const wrapper = mount(InputTextarea, { - props: { - rules: {}, - name: 'input-field-name', - label: 'input-field-label', - placeholder: 'input-field-placeholder', - }, - global: { - components: { - BFormGroup, - BFormInvalidFeedback, - BFormTextarea, - }, - }, - }) - - const textarea = wrapper.find('textarea') - await textarea.setValue('New Text') - - expect(wrapper.vm.currentValue).toBe('New Text') - }) - }) - - describe('disabled state', () => { - it('disables the textarea when disabled prop is true', async () => { - await wrapper.setProps({ disabled: true }) - const textarea = wrapper.findComponent({ name: 'BFormTextarea' }) - expect(textarea.attributes('disabled')).toBeDefined() - }) - }) - - it('shows error message when there is an error', async () => { - vi.mocked(useField).mockReturnValue({ - value: '', - errorMessage: 'This field is required', - meta: { valid: false }, - }) - - wrapper = createWrapper() - await wrapper.vm.$nextTick() - - const errorFeedback = wrapper.findComponent({ name: 'BFormInvalidFeedback' }) - expect(errorFeedback.exists()).toBe(true) - expect(errorFeedback.text()).toBe('This field is required') - }) -}) diff --git a/frontend/src/components/Inputs/InputTextarea.vue b/frontend/src/components/Inputs/InputTextarea.vue deleted file mode 100644 index e44179fc0..000000000 --- a/frontend/src/components/Inputs/InputTextarea.vue +++ /dev/null @@ -1,64 +0,0 @@ - - - - - diff --git a/frontend/src/locales/de.json b/frontend/src/locales/de.json index 8b441b982..a94099015 100644 --- a/frontend/src/locales/de.json +++ b/frontend/src/locales/de.json @@ -203,6 +203,11 @@ "username": "Benutzername", "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" + }, "gddCreationTime": { "min": "Die Stunden sollten mindestens {min} groß sein", "max": "Die Stunden sollten höchstens {max} groß sein", diff --git a/frontend/src/locales/en.json b/frontend/src/locales/en.json index ca4877682..ec26e866d 100644 --- a/frontend/src/locales/en.json +++ b/frontend/src/locales/en.json @@ -203,6 +203,11 @@ "username": "Username", "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" + }, "gddCreationTime": { "min": "The hours should be at least {min} in size", "max": "The hours should not be larger than {max}", diff --git a/frontend/src/validationSchemas.js b/frontend/src/validationSchemas.js index 01a1ec8ab..9c21aec66 100644 --- a/frontend/src/validationSchemas.js +++ b/frontend/src/validationSchemas.js @@ -1,4 +1,10 @@ import { string } from 'yup' +import { validate as validateUuid, version as versionUuid } from 'uuid' + +// Email and username regex patterns remain the same +const EMAIL_REGEX = + /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/ +const USERNAME_REGEX = /^(?=.{3,20}$)[a-zA-Z0-9]+(?:[_-][a-zA-Z0-9]+?)*$/ // TODO: only needed for grace period, before all inputs updated for using veeValidate + yup export const isLanguageKey = (str) => @@ -19,3 +25,15 @@ export const memo = string() .required('contribution.yourActivity') .min(5, ({ min }) => ({ key: 'form.validation.memo.min', values: { min } })) .max(255, ({ max }) => ({ key: 'form.validation.memo.max', values: { max } })) + +export const identifier = string().test( + 'valid-identifier', + 'form.validation.valid-identifier', + (value) => { + const isEmail = !!EMAIL_REGEX.test(value) + const isUsername = !!value.match(USERNAME_REGEX) + // TODO: use valibot and rules from shared + const isGradidoId = validateUuid(value) && versionUuid(value) === 4 + return isEmail || isUsername || isGradidoId + }, +)