web/satellite: rewrite VInput with composition API

This change updates VInput with composition API, and fix resulting test failures.

see: https://github.com/storj/storj/issues/5115

Change-Id: Ic6870f4faef51de168ef077952b7ce6a39562e6e
This commit is contained in:
Wilfred Asomani 2022-09-30 20:52:21 +00:00 committed by Storj Robot
parent b23b3e02e6
commit fac638fc7d
15 changed files with 155 additions and 140 deletions

View File

@ -64,7 +64,6 @@ module.exports = {
],
'newlines-between': 'always',
}],
'no-duplicate-imports': 'error',
'object-curly-spacing': ['error', 'always'],
'quotes': ['error', 'single', { 'allowTemplateLiterals': true }],

View File

@ -15,7 +15,7 @@
:label="inputLabel"
placeholder="Enter Coupon Code"
height="52px"
:with-icon="true"
with-icon
@setData="setCouponCode"
/>
<CheckIcon

View File

@ -10,7 +10,7 @@
<VInput
placeholder="Enter Coupon Code"
height="52px"
:with-icon="false"
with-icon
@setData="setCouponCode"
/>
</div>

View File

@ -53,7 +53,7 @@
placeholder="Enter a passphrase here..."
:error="enterError"
role-description="passphrase"
is-password="true"
is-password
:disabled="isLoading"
@setData="setPassphrase"
/>

View File

@ -65,125 +65,136 @@
</template>
<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator';
import PasswordHiddenIcon from '@/../static/images/common/passwordHidden.svg';
import PasswordShownIcon from '@/../static/images/common/passwordShown.svg';
import { computed, defineComponent, onBeforeMount, ref } from 'vue';
import ErrorIcon from '@/../static/images/register/ErrorInfo.svg';
import PasswordShownIcon from '@/../static/images/common/passwordShown.svg';
import PasswordHiddenIcon from '@/../static/images/common/passwordHidden.svg';
// @vue/component
@Component({
const textType = 'text';
const passwordType = 'password';
export default defineComponent({
name: 'VInput',
components: {
ErrorIcon,
PasswordHiddenIcon,
PasswordShownIcon,
ErrorIcon,
},
})
// TODO: merge these two components to have one single source of truth.
export default class VInput extends Vue {
@Prop({ default: '' })
private readonly additionalLabel: string;
@Prop({ default: 0 })
private readonly currentLimit: number;
@Prop({ default: false })
private readonly isOptional: boolean;
@Prop({ default: false })
private readonly isLimitShown: boolean;
@Prop({ default: false })
private readonly isMultiline: boolean;
@Prop({ default: false })
private readonly isLoading: boolean;
@Prop({ default: '' })
protected readonly initValue: string;
@Prop({ default: '' })
protected readonly label: string;
@Prop({ default: 'default' })
protected readonly placeholder: string;
@Prop({ default: false })
protected readonly isPassword: boolean;
@Prop({ default: '48px' })
protected readonly height: string;
@Prop({ default: '100%' })
protected readonly width: string;
@Prop({ default: '' })
protected readonly error: string;
@Prop({ default: Number.MAX_SAFE_INTEGER })
protected readonly maxSymbols: number;
@Prop({ default: false })
private readonly isWhite: boolean;
@Prop({ default: false })
private readonly withIcon: boolean;
@Prop({ default: false })
private readonly disabled: boolean;
@Prop({ default: 'input-container' })
private readonly roleDescription: boolean;
private readonly textType: string = 'text';
private readonly passwordType: string = 'password';
private type: string = this.textType;
private isPasswordShown = false;
public value: string;
public created() {
this.type = this.isPassword ? this.passwordType : this.textType;
this.value = this.initValue;
}
public showPasswordStrength(): void {
this.$emit('showPasswordStrength');
}
public hidePasswordStrength(): void {
this.$emit('hidePasswordStrength');
}
/**
* triggers on input.
*/
public onInput(event: Event): void {
const target = event.target as HTMLInputElement;
this.value = target.value;
this.$emit('setData', this.value);
}
/**
* Triggers input type between text and password to show/hide symbols.
*/
public changeVision(): void {
this.isPasswordShown = !this.isPasswordShown;
this.type = this.isPasswordShown ? this.textType : this.passwordType;
}
public get isPasswordHiddenState(): boolean {
return this.isPassword && !this.isPasswordShown;
}
public get isPasswordShownState(): boolean {
return this.isPassword && this.isPasswordShown;
}
props: {
additionalLabel: {
type: String,
default: '',
},
currentLimit: {
type: Number,
default: 0,
},
isOptional: Boolean,
isLimitShown: Boolean,
isMultiline: Boolean,
isLoading: Boolean,
initValue: {
type: String,
default: '',
},
label: {
type: String,
default: '',
},
placeholder: {
type: String,
default: 'default',
},
isPassword: Boolean,
height: {
type: String,
default: '48px',
},
width: {
type: String,
default: '100%',
},
error: {
type: String,
default: '',
},
maxSymbols: {
type: Number,
default: Number.MAX_SAFE_INTEGER,
},
isWhite: Boolean,
withIcon: Boolean,
disabled: Boolean,
roleDescription: {
type: String,
default: 'input-container',
},
},
emits: ['showPasswordStrength', 'hidePasswordStrength', 'setData'],
setup(props, ctx) {
const value = ref('');
const isPasswordShown = ref(false);
const type = ref(textType);
onBeforeMount(() => {
type.value = props.isPassword ? passwordType : textType;
value.value = props.initValue;
});
return {
isPasswordHiddenState: computed(() => {
return props.isPassword && !isPasswordShown.value;
}),
isPasswordShownState: computed(() => {
return props.isPassword && isPasswordShown.value;
}),
/**
* Returns style objects depends on props.
*/
protected get style(): Record<string, unknown> {
style: computed(() => {
return {
inputStyle: {
width: this.width,
height: this.height,
padding: this.withIcon ? '0 30px 0 50px' : '',
width: props.width,
height: props.height,
padding: props.withIcon ? '0 30px 0 50px' : '',
},
labelStyle: {
color: this.isWhite ? 'white' : '#354049',
color: props.isWhite ? 'white' : '#354049',
},
errorStyle: {
color: this.isWhite ? 'white' : '#FF5560',
color: props.isWhite ? 'white' : '#FF5560',
},
};
}
}
}),
showPasswordStrength(): void {
ctx.emit('showPasswordStrength');
},
hidePasswordStrength(): void {
ctx.emit('hidePasswordStrength');
},
/**
* triggers on input.
*/
onInput(event: Event): void {
const target = event.target as HTMLInputElement;
value.value = target.value;
ctx.emit('setData', value.value);
},
/**
* Triggers input type between text and password to show/hide symbols.
*/
changeVision(): void {
isPasswordShown.value = !isPasswordShown.value;
type.value = isPasswordShown.value ? textType : passwordType;
},
value,
isPasswordShown,
type,
};
},
});
</script>
<style scoped lang="scss">

View File

@ -13,7 +13,7 @@
class="full-input"
label="Old Password"
placeholder="Old Password"
is-password="true"
is-password
:error="oldPasswordError"
@setData="setOldPassword"
/>
@ -22,7 +22,7 @@
class="full-input"
label="New Password"
placeholder="New Password"
is-password="true"
is-password
:error="newPasswordError"
@setData="setNewPassword"
@showPasswordStrength="showPasswordStrength"
@ -37,7 +37,7 @@
class="full-input"
label="Confirm Password"
placeholder="Confirm Password"
is-password="true"
is-password
:error="confirmationPasswordError"
@setData="setPasswordConfirmation"
/>

View File

@ -18,7 +18,7 @@
additional-label="Up To 20 Characters"
placeholder="Project Name"
class="full-input"
is-limit-shown="true"
is-limit-shown
:current-limit="projectName.length"
:max-symbols="20"
:error="nameError"
@ -28,9 +28,9 @@
label="Description - Optional"
placeholder="Project Description"
class="full-input"
is-multiline="true"
is-multiline
height="100px"
is-limit-shown="true"
is-limit-shown
:current-limit="description.length"
:max-symbols="100"
@setData="setProjectDescription"

View File

@ -15,14 +15,14 @@
label="Bucket Name"
:init-value="bucketName"
role-description="bucket"
disabled="true"
:disabled="true"
/>
<VInput
label="Encryption Passphrase"
placeholder="Enter a passphrase here"
:error="enterError"
role-description="passphrase"
is-password="true"
is-password
:disabled="isLoading"
@setData="setPassphrase"
/>

View File

@ -72,7 +72,7 @@
placeholder="Enter a passphrase here..."
:error="enterError"
role-description="passphrase"
is-password="true"
is-password
:disabled="isLoading"
@setData="setPassphrase"
/>

View File

@ -17,7 +17,7 @@
additional-label="Up To 20 Characters"
placeholder="Enter Project Name"
class="full-input"
is-limit-shown="true"
is-limit-shown
:current-limit="projectName.length"
:max-symbols="20"
:error="nameError"
@ -28,9 +28,9 @@
placeholder="Enter Project Description"
additional-label="Optional"
class="full-input"
is-multiline="true"
is-multiline
height="100px"
is-limit-shown="true"
is-limit-shown
:current-limit="description.length"
:max-symbols="100"
@setData="setProjectDescription"

View File

@ -61,7 +61,7 @@
role-description="passphrase"
placeholder="Passphrase"
:error="passphraseErr"
is-password="true"
is-password
@setData="setPassphrase"
/>
</div>

View File

@ -75,7 +75,7 @@
label="Password"
placeholder="Password"
:error="passwordError"
is-password="true"
is-password
role-description="password"
@setData="setPassword"
/>

View File

@ -42,7 +42,7 @@
label="Password"
placeholder="Enter Password"
:error="passwordError"
is-password="true"
is-password
@setData="setPassword"
@showPasswordStrength="showPasswordStrength"
@hidePasswordStrength="hidePasswordStrength"
@ -57,7 +57,7 @@
label="Retype Password"
placeholder="Retype Password"
:error="repeatedPasswordError"
is-password="true"
is-password
@setData="setRepeatedPassword"
/>
</div>

View File

@ -162,7 +162,7 @@
label="Password"
placeholder="Enter Password"
:error="passwordError"
is-password="true"
is-password
role-description="password"
@setData="setPassword"
@showPasswordStrength="showPasswordStrength"
@ -179,7 +179,7 @@
label="Retype Password"
placeholder="Retype Password"
:error="repeatedPasswordError"
is-password="true"
is-password
role-description="retype-password"
@setData="setRepeatedPassword"
/>

View File

@ -1,22 +1,23 @@
// Copyright (C) 2022 Storj Labs, Inc.
// See LICENSE for copying information.
import { mount, shallowMount } from '@vue/test-utils';
import { shallowMount } from '@vue/test-utils';
import VInput from '@/components/common/VInput.vue';
describe('VInput.vue', () => {
it('renders correctly with default props', () => {
const wrapper = shallowMount(VInput);
const wrapper = shallowMount(VInput as never);
expect(wrapper).toMatchSnapshot();
});
it('renders correctly with isMultiline props', () => {
const wrapper = shallowMount(VInput, {
propsData: { isMultiline: true },
const wrapper = shallowMount(VInput as never, {
propsData: {
isMultiline: true,
},
});
expect(wrapper).toMatchSnapshot();
@ -30,8 +31,13 @@ describe('VInput.vue', () => {
const width = '30px';
const height = '20px';
const wrapper = shallowMount(VInput, {
propsData: { label, width, height, additionalLabel },
const wrapper = shallowMount(VInput as never, {
propsData : {
label,
additionalLabel,
width,
height,
},
});
const el = wrapper.find('input').element as HTMLElement;
@ -43,8 +49,7 @@ describe('VInput.vue', () => {
});
it('renders correctly with isOptional props', () => {
const wrapper = shallowMount(VInput, {
const wrapper = shallowMount(VInput as never, {
propsData: {
isOptional: true,
},
@ -56,7 +61,7 @@ describe('VInput.vue', () => {
it('renders correctly with input error', () => {
const error = 'testError';
const wrapper = shallowMount(VInput, {
const wrapper = shallowMount(VInput as never, {
propsData: {
error,
},
@ -69,7 +74,7 @@ describe('VInput.vue', () => {
it('emit setData on input correctly', async () => {
const testData = 'testData';
const wrapper = mount(VInput);
const wrapper = shallowMount(VInput as never);
await wrapper.find('input').trigger('input');